Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> iOS

Cách thực hiện HTTP Request trong iOS App bằng Swift

Để thực hiện HTTP request trong iOS, dùng URLSession + URLSessionDataTask (native, không cần thư viện). Hỗ trợ GET, POST, PUT, DELETE, PATCH...

Quy trình chung (Ví dụ DELETE)

  1. Tạo Session

let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
// Hoặc dùng shared session cho đơn giản: URLSession.shared
  1. Tạo URLRequest

let urlString = "https://api.example.com/items/123"
guard let url = URL(string: urlString) else { return }

var request = URLRequest(url: url)
request.httpMethod = "DELETE"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
// Auth header:
request.setValue("Bearer \(authToken)", forHTTPHeaderField: "Authorization")
  1. Tạo DataTask & Resume

let task = session.dataTask(with: request) { data, response, error in
    // 1. Network error
    if let error = error {
        print("Network error: \(error)")
        return
    }
    
    // 2. HTTP Response validation
    guard let httpResponse = response as? HTTPURLResponse else {
        print("Invalid response")
        return
    }
    
    print("Status: \(httpResponse.statusCode)")
    
    // 3. Handle status codes
    switch httpResponse.statusCode {
    case 200, 204:  // 204 No Content thường dùng cho DELETE thành công
        print("Xóa thành công")
        DispatchQueue.main.async { /* Update UI */ }
    case 400: print("Bad Request")
    case 401: print("Unauthorized - token hết hạn")
    case 404: print("Not Found")
    case 500: print("Server Error")
    default: print("Status khác: \(httpResponse.statusCode)")
    }
    
    // 4. Parse response data nếu có
    if let data = data, let json = try? JSONSerialization.jsonObject(with: data) {
        print("Response: \(json)")
    }
}

task.resume()  // BẮT BUỘC: Khởi chạy task

Hàm generic tái sử dụng (Swift 5+)


enum NetworkError: Error {
    case invalidURL, invalidResponse, statusCode(Int), decoding(Error), network(Error)
}

func request(
    url: String,
    method: String = "GET",
    headers: [String: String] = [:],
    body: Data? = nil,
    completion: @escaping (Result) -> Void
) {
    guard let url = URL(string: url) else { completion(.failure(.invalidURL)); return }
    
    var request = URLRequest(url: url)
    request.httpMethod = method
    request.httpBody = body
    headers.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error { completion(.failure(.network(error))); return }
        
        guard let httpResponse = response as? HTTPURLResponse else {
            completion(.failure(.invalidResponse)); return
        }
        
        guard (200...299).contains(httpResponse.statusCode) else {
            completion(.failure(.statusCode(httpResponse.statusCode))); return
        }
        
        guard let data = data else { completion(.failure(.invalidResponse)); return }
        
        do {
            let decoded = try JSONDecoder().decode(T.self, from: data)
            completion(.success(decoded))
        } catch {
            completion(.failure(.decoding(error)))
        }
    }.resume()
}

// Sử dụng:
struct User: Decodable { let id: Int; let name: String }
request(url: "https://api.example.com/user/1", method: "GET") { (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

  • ATS (App Transport Security): Info.plist NSAppTransportSecurity cho HTTP hoặc domain exception.
  • Main Thread: Cập nhật UI trong completion phải DispatchQueue.main.async.
  • Cancel: Giữ reference task để task.cancel() khi cần (ví dụ: user thoát màn hình).
  • Thư viện production: Alamofire (wrapper đẹp), Moya (type-safe, testable), Apollo (GraphQL).