ใช้ URLSession (Native) สำหรับ Network Request ไม่ต้องใช้ Library ภายนอก
โครงสร้างพื้นฐาน
import Foundation
struct APIService {
static let shared = APIService()
private let session = URLSession.shared
func request(_ endpoint: Endpoint, completion: @escaping (Result) -> Void) {
guard let url = endpoint.url else {
completion(.failure(URLError(.badURL)))
return
}
var request = URLRequest(url: url)
request.httpMethod = endpoint.method.rawValue
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
if let body = endpoint.body {
request.httpBody = try? JSONEncoder().encode(body)
}
session.dataTask(with: request) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
guard let httpResponse = response as? HTTPURLResponse else {
completion(.failure(URLError(.badServerResponse)))
return
}
guard (200...299).contains(httpResponse.statusCode) else {
let apiError = APIError(statusCode: httpResponse.statusCode, data: data)
completion(.failure(apiError))
return
}
guard let data = data else {
completion(.failure(URLError(.zeroByteResource)))
return
}
do {
let decoded = try JSONDecoder().decode(T.self, from: data)
completion(.success(decoded))
} catch {
completion(.failure(error))
}
}.resume()
}
}
// Endpoint Enum
enum HTTPMethod: String { case get = "GET", post = "POST", put = "PUT", delete = "DELETE" }
struct Endpoint {
let path: String
let method: HTTPMethod
let body: Encodable?
var url: URL? { URL(string: "https://api.example.com" + path) }
}
การใช้งาน
// GET
APIService.shared.request(Endpoint(path: "/users/1", method: .get, body: nil)) { (result: Result) in
switch result {
case .success(let user): print(user.name)
case .failure(let error): print("Error: \(error)")
}
}
// POST
struct CreateUserRequest: Encodable { let name: String; let email: String }
APIService.shared.request(Endpoint(path: "/users", method: .post, body: CreateUserRequest(name: "John", email: "john@example.com"))) { (result: Result) in ... }
Modern Concurrency (Swift 5.5+ async/await)
func requestAsync(_ endpoint: Endpoint) async throws -> T {
guard let url = endpoint.url else { throw URLError(.badURL) }
var request = URLRequest(url: url)
request.httpMethod = endpoint.method.rawValue
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode(T.self, from: data)
}
// ใช้งาน
Task {
do {
let user = try await APIService.shared.requestAsync(Endpoint(path: "/users/1", method: .get, body: nil))
print(user)
} catch { print(error) }
}
Info.plist (App Transport Security)
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>api.example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
แนะนำ: ใช้ HTTPS เท่านั้น ไม่ควรใช้ NSAllowsArbitraryLoads
Library แนะนำ (Production)
- Alamofire - Wrapper URLSession ยอดนิยม
- Moya - Network Abstraction Layer
- Apollo - GraphQL Client