Search code examples
swiftxcodeapihttpresponsefunc

Taking Swift HTTP POST and Decoding JSON Response


From some previous help, I was able to build out this to submit an API POST request from within the swift platform.

import Foundation

struct requestbody: Codable {
    let data: DataClass
}

// MARK: - DataClass
struct DataClass: Codable {
    let slices: [Slice]
    let passengers: [Passenger]
    let cabinClass: String

    enum CodingKeys: String, CodingKey {
        case slices, passengers
        case cabinClass = "cabin_class"
    }
}

// MARK: - Passenger
struct Passenger: Codable {
    let type: String
}

// MARK: - Slice
struct Slice: Codable {
    let origin, destination, departureDate: String

    enum CodingKeys: String, CodingKey {
        case origin, destination
        case departureDate = "departure_date"
    }
}
class APIPost {

func getposts(response: requestbody) -> URLRequest? {
        guard let url = URL(string: "https://api.duffel.com/air/offer_requests") else { return nil }
        var request = URLRequest(url: url)
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        request.setValue("beta", forHTTPHeaderField: "Duffel-Version")
        request.setValue("Bearer [redacted]", forHTTPHeaderField: "Authorization")
        request.httpMethod = "POST"
        request.httpBody = try! JSONEncoder().encode(response)
        return request
}

I will, however, say I am somewhat stumped when it comes to how to integrate this method to then decode the JSON response, to then use in a UI. I cannot add a completion parameter in the function (to add @escaping) either, and believe maybe it would be best to take this action and build off it in another function. Any high level (or detailed) responses would be greatly greatly appreciated.

Thank you!


Solution

  • Creating a URLRequest instance is not enough, you have to send this request to your server as well. You can send it via URLSession API.

    // Notice the change in function signature
    func getPost(requestBody: RequestBody, completion: @escaping ((_ posts: [Post]?, _ error: Error?) -> Void)) -> URLRequest? {
        
        // Everything else same up to this point
        request.httpBody = try! JSONEncoder().encode(requestBody)
        
        // Send the request to your server
        URLSession.shared.dataTask(with: request, completionHandler: { (data, urlResponse, error) in
           
            // Check if there was an error from network/server
            if let error = error {
                print(error.localizedDescription)
                // call completion with error from network/server
                completion(nil, error)
                return // return early because there was an error
            }
            
            // No error if we are, check for data
            if let data = data {
                do {
                    // Try decoding your data to your model
                    let posts = try JSONDecoder().decode([Post].self, from: data)
                    // call completion with your models array, no error
                    completion(posts, nil)
                }
                catch {
                    // there's a decoding error, call completion with decoding error
                    completion(nil, error)
                }
            }
        }).resume() // resuming a dataTask is essential, otherwise the call won't be sent to server
        
        return request
    }