Để gọi REST API trong Swift, cách native là dùng URLSession với DataTask. REST (Representational State Transfer) định nghĩa các ràng buộc cho web service. Dưới đây là quy trình cơ bản.
Các bước gọi API (GET example)
- Tạo URLSessionConfiguration & Session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
- Tạo URLRequest
let urlString = "https://api.example.com/users"
guard let url = URL(string: urlString) else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
// Thêm header auth nếu cần:
// request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
- Tạo DataTask & Resume
let task = session.dataTask(with: request) { data, response, error in
// 1. Kiểm tra error network
if let error = error {
print("Network error: \(error)")
return
}
// 2. Kiểm tra HTTP response
guard let httpResponse = response as? HTTPURLResponse else {
print("Invalid response")
return
}
print("Status code: \(httpResponse.statusCode)")
// 3. Xử lý data
guard let data = data else { return }
do {
// Parse JSON
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
print("Response JSON: \(json)")
// Cập nhật UI trên main thread
DispatchQueue.main.async {
// self.updateUI(with: json)
}
}
} catch {
print("JSON parse error: \(error)")
}
}
task.resume() // Quan trọng: bắt đầu task
Gói thành hàm tái sử dụng
func callAPI(_ urlString: String,
method: String = "GET",
body: Data? = nil,
completion: @escaping (Result) -> Void) {
guard let url = URL(string: urlString) else {
completion(.failure(URLError(.badURL)))
return
}
var request = URLRequest(url: url)
request.httpMethod = method
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = body
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode),
let data = data else {
let status = (response as? HTTPURLResponse)?.statusCode ?? -1
completion(.failure(NSError(domain: "APIError", code: status, userInfo: nil)))
return
}
do {
let decoded = try JSONDecoder().decode(T.self, from: data)
completion(.success(decoded))
} catch {
completion(.failure(error))
}
}.resume()
}
// Sử dụng với Codable model:
struct User: Codable { let id: Int; let name: String; let email: String }
callAPI("https://jsonplaceholder.typicode.com/users/1") { (result: Result) in
switch result {
case .success(let user): print("User: \(user.name)")
case .failure(let err): print("Error: \(err)")
}
}
Lưu ý quan trọng
- App Transport Security (ATS): iOS mặc định chặn HTTP không mã hóa. Cần thêm
NSAppTransportSecuritytrong Info.plist cho HTTP hoặc domain exception. - JSONDecoder/Encoder: Dùng
Codableprotocol cho type-safe parsing thay vìJSONSerialization. - Background thread:
dataTaskchạy trên background, cập nhật UI phải dispatch về main. - Thư viện phổ biến: Alamofire (wrapper URLSession), Moya (network abstraction), Apollo (GraphQL).