Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> iOS

วิธีเรียก RESTful API ใน iOS/iPhone ด้วย Swift

ใช้ 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