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

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!