Tutorial 14: Networking in iOS - Making API Calls with URLSession

Introduction Networking is a fundamental part of modern iOS applications. Whether you are fetching data from a REST API, sending user input to a backend, or streaming live updates, mastering networking in Swift is crucial. In this tutorial, we will explore how to use URLSession to make API calls and build an Instant Messaging App that allows users to fetch and send messages. By the end of this tutorial, you will learn: How to use URLSession for making GET and POST requests. How to parse JSON responses using Codable. How to implement a simple messaging interface. Best practices for handling errors and concurrency in networking. Prerequisites To follow along, ensure you have: Xcode installed (latest version recommended). Basic understanding of Swift and SwiftUI. A mock or real API endpoint to work with (we will use a mock server for this tutorial). 1. Setting Up the Project Open Xcode and create a new project using App template with SwiftUI as the interface and Swift as the language. Name the project InstantMessenger. 2. Understanding URLSession URLSession is the native networking API in Swift that allows you to perform HTTP requests. It provides an efficient way to handle networking tasks asynchronously. Key Components URLRequest: Represents an HTTP request. URLSessionDataTask: Handles data retrieval. URLSession: Manages network sessions. Codable: Used to parse JSON data. 3. Creating a Mock API For this tutorial, we will use a free online REST API service like jsonplaceholder.typicode.com or create a mock server with Mockoon. Example API Endpoints GET /messages: Fetches a list of messages. POST /messages: Sends a new message. 4. Defining the Message Model Create a Swift file named Message.swift and define the model: import Foundation struct Message: Codable, Identifiable { let id: Int let sender: String let content: String let timestamp: Date } 5. Implementing Networking Layer Create a file NetworkManager.swift to handle API requests. import Foundation class NetworkManager { static let shared = NetworkManager() private let baseURL = "https://jsonplaceholder.typicode.com" func fetchMessages(completion: @escaping ([Message]?) -> Void) { guard let url = URL(string: "\(baseURL)/messages") else { return } let task = URLSession.shared.dataTask(with: url) { data, response, error in guard let data = data, error == nil else { completion(nil) return } let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 do { let messages = try decoder.decode([Message].self, from: data) DispatchQueue.main.async { completion(messages) } } catch { completion(nil) } } task.resume() } func sendMessage(message: Message, completion: @escaping (Bool) -> Void) { guard let url = URL(string: "\(baseURL)/messages") else { return } var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") let encoder = JSONEncoder() encoder.dateEncodingStrategy = .iso8601 do { request.httpBody = try encoder.encode(message) } catch { completion(false) return } let task = URLSession.shared.dataTask(with: request) { data, response, error in completion(error == nil) } task.resume() } } 6. Creating the Messaging Interface Create a SwiftUI view called ChatView.swift. import SwiftUI struct ChatView: View { @State private var messages: [Message] = [] @State private var newMessage: String = "" var body: some View { VStack { List(messages) { message in VStack(alignment: .leading) { Text(message.sender).font(.headline) Text(message.content) Text("\(message.timestamp, formatter: dateFormatter)").font(.caption) } } HStack { TextField("Type a message...", text: $newMessage) .textFieldStyle(RoundedBorderTextFieldStyle()) Button("Send") { sendMessage() } } .padding() } .onAppear { fetchMessages() } } func fetchMessages() { NetworkManager.shared.fetchMessages { fetchedMessages in if let fetchedMessages = fetchedMessages { self.messages = fetchedMessages } } } func sendMessage() { let message = Message(id: messages.count + 1, sender: "User", cont

Mar 31, 2025 - 21:17
 0
Tutorial 14: Networking in iOS - Making API Calls with URLSession

Introduction

Networking is a fundamental part of modern iOS applications. Whether you are fetching data from a REST API, sending user input to a backend, or streaming live updates, mastering networking in Swift is crucial. In this tutorial, we will explore how to use URLSession to make API calls and build an Instant Messaging App that allows users to fetch and send messages.

By the end of this tutorial, you will learn:

  • How to use URLSession for making GET and POST requests.
  • How to parse JSON responses using Codable.
  • How to implement a simple messaging interface.
  • Best practices for handling errors and concurrency in networking.

Prerequisites

To follow along, ensure you have:

  • Xcode installed (latest version recommended).
  • Basic understanding of Swift and SwiftUI.
  • A mock or real API endpoint to work with (we will use a mock server for this tutorial).

1. Setting Up the Project

Open Xcode and create a new project using App template with SwiftUI as the interface and Swift as the language. Name the project InstantMessenger.

2. Understanding URLSession

URLSession is the native networking API in Swift that allows you to perform HTTP requests. It provides an efficient way to handle networking tasks asynchronously.

Key Components

  • URLRequest: Represents an HTTP request.
  • URLSessionDataTask: Handles data retrieval.
  • URLSession: Manages network sessions.
  • Codable: Used to parse JSON data.

3. Creating a Mock API

For this tutorial, we will use a free online REST API service like jsonplaceholder.typicode.com or create a mock server with Mockoon.

Example API Endpoints

  • GET /messages: Fetches a list of messages.
  • POST /messages: Sends a new message.

4. Defining the Message Model

Create a Swift file named Message.swift and define the model:

import Foundation

struct Message: Codable, Identifiable {
    let id: Int
    let sender: String
    let content: String
    let timestamp: Date
}

5. Implementing Networking Layer

Create a file NetworkManager.swift to handle API requests.

import Foundation

class NetworkManager {
    static let shared = NetworkManager()
    private let baseURL = "https://jsonplaceholder.typicode.com"

    func fetchMessages(completion: @escaping ([Message]?) -> Void) {
        guard let url = URL(string: "\(baseURL)/messages") else { return }

        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data, error == nil else {
                completion(nil)
                return
            }

            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601

            do {
                let messages = try decoder.decode([Message].self, from: data)
                DispatchQueue.main.async {
                    completion(messages)
                }
            } catch {
                completion(nil)
            }
        }
        task.resume()
    }

    func sendMessage(message: Message, completion: @escaping (Bool) -> Void) {
        guard let url = URL(string: "\(baseURL)/messages") else { return }
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        let encoder = JSONEncoder()
        encoder.dateEncodingStrategy = .iso8601

        do {
            request.httpBody = try encoder.encode(message)
        } catch {
            completion(false)
            return
        }

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            completion(error == nil)
        }
        task.resume()
    }
}

6. Creating the Messaging Interface

Create a SwiftUI view called ChatView.swift.

import SwiftUI

struct ChatView: View {
    @State private var messages: [Message] = []
    @State private var newMessage: String = ""

    var body: some View {
        VStack {
            List(messages) { message in
                VStack(alignment: .leading) {
                    Text(message.sender).font(.headline)
                    Text(message.content)
                    Text("\(message.timestamp, formatter: dateFormatter)").font(.caption)
                }
            }

            HStack {
                TextField("Type a message...", text: $newMessage)
                    .textFieldStyle(RoundedBorderTextFieldStyle())

                Button("Send") {
                    sendMessage()
                }
            }
            .padding()
        }
        .onAppear {
            fetchMessages()
        }
    }

    func fetchMessages() {
        NetworkManager.shared.fetchMessages { fetchedMessages in
            if let fetchedMessages = fetchedMessages {
                self.messages = fetchedMessages
            }
        }
    }

    func sendMessage() {
        let message = Message(id: messages.count + 1, sender: "User", content: newMessage, timestamp: Date())
        NetworkManager.shared.sendMessage(message: message) { success in
            if success {
                self.messages.append(message)
                self.newMessage = ""
            }
        }
    }
}

private let dateFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    formatter.timeStyle = .short
    return formatter
}()

7. Running the App

  • Build and run the app in the iOS Simulator.
  • Observe messages being fetched and new messages being sent.
  • Ensure API responses are handled properly.

8. Error Handling and Improvements

  • Add error messages when network requests fail.
  • Implement retry logic or offline caching with Core Data.
  • Improve UI with animations and chat bubbles.

Conclusion

In this tutorial, we built an Instant Messaging App using URLSession to fetch and send messages. You learned:

  • How to structure a networking layer in Swift.
  • How to use URLSession for API calls.
  • How to handle JSON parsing with Codable.
  • How to build a simple chat UI with SwiftUI.

This foundational knowledge will help you integrate networking in real-world iOS applications. Happy coding!