Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Codable for API request

Tags:

ios

swift

codable

How would I make this same API request through codables? In my app, this function is repeated in every view that makes API calls.

func getOrders() {

        DispatchQueue.main.async {

            let spinningHUD = MBProgressHUD.showAdded(to: self.view, animated: true)
            spinningHUD.isUserInteractionEnabled = false

            let returnAccessToken: String? = UserDefaults.standard.object(forKey: "accessToken") as? String

            let access  = returnAccessToken!
            let headers = [
                "postman-token": "dded3e97-77a5-5632-93b7-dec77d26ba99",
                "Authorization": "JWT \(access)"
            ]

            let request = NSMutableURLRequest(url: NSURL(string: "https://somelink.com")! as URL,
                                              cachePolicy: .useProtocolCachePolicy,
                                              timeoutInterval: 10.0)

            request.httpMethod          = "GET"
            request.allHTTPHeaderFields = headers

            let session  = URLSession.shared
            let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
                if (error != nil) {
                    print(error!)

                } else {
                    if let dataNew = data, let responseString = String(data: dataNew, encoding: .utf8) {
                        print("----- Orders -----")
                        print(responseString)
                        print("----------")

                        let dict = self.convertToDictionary(text: responseString)
                        print(dict?["results"] as Any)
                        guard let results = dict?["results"] as? NSArray else { return }
                        self.responseArray = (results) as! [HomeVCDataSource.JSONDictionary]

                        DispatchQueue.main.async {
                            spinningHUD.hide(animated: true)
                            self.tableView.reloadData()
                        }

                    }

                }

            })

            dataTask.resume()
        }
    }
like image 477
Jessica Kimble Avatar asked May 07 '26 07:05

Jessica Kimble


1 Answers

I would suggest to do the following

  1. Create Base Service as below

import UIKit
import Foundation

enum MethodType: String {
    case get     = "GET"
    case post    = "POST"
    case put     = "PUT"
    case patch   = "PATCH"
    case delete  = "DELETE"
}

class BaseService {

    var session: URLSession!

    // MARK: Rebuilt Methods
    func FireGenericRequest<ResponseModel: Codable>(url: String, methodType: MethodType, headers: [String: String]?, completion: @escaping ((ResponseModel?) -> Void)) {
        UIApplication.shared.isNetworkActivityIndicatorVisible = true

        // Request Preparation
        guard let serviceUrl = URL(string: url) else {
            print("Error Building URL Object")
            return
        }
        var request = URLRequest(url: serviceUrl)
        request.httpMethod = methodType.rawValue

        // Header Preparation
        if let header = headers {
            for (key, value) in header {
                request.setValue(value, forHTTPHeaderField: key)
            }
        }

        // Firing the request
        session = URLSession(configuration: URLSessionConfiguration.default)
        session.dataTask(with: request) { (data, response, error) in
            DispatchQueue.main.async {
                UIApplication.shared.isNetworkActivityIndicatorVisible = false
            }
            if let data = data {
                do {
                    guard let object = try? JSONDecoder().decode(ResponseModel.self , from: data) else {
                        print("Error Decoding Response Model Object")
                        return
                    }
                    DispatchQueue.main.async {
                        completion(object)
                    }
                }
            }
        }.resume()
    }

    private func buildGenericParameterFrom<RequestModel: Codable>(model: RequestModel?) -> [String : AnyObject]? {
        var object: [String : AnyObject] = [String : AnyObject]()
        do {
            if let dataFromObject = try? JSONEncoder().encode(model) {
                object = try JSONSerialization.jsonObject(with: dataFromObject, options: []) as! [String : AnyObject]
            }
        } catch (let error) {
            print("\nError Encoding Parameter Model Object \n \(error.localizedDescription)\n")
        }
        return object
    }

}


the above class you may reuse it in different scenarios adding request object to it and passing any class you would like as long as you are conforming to Coddle protocol

  1. Create Model Conforming to Coddle protocol

class ExampleModel: Codable {
    var commentId : String?
    var content : String?

    //if your JSON keys are different than your property name
    enum CodingKeys: String, CodingKey {
        case commentId = "CommentId" 
        case content = "Content"
    }

}

  1. Create Service to the specific model with the endpoint constants subclassing to BaseService as below

class ExampleModelService: BaseService<ExampleModel/* or [ExampleModel]*/> {

    func GetExampleModelList(completion: ((ExampleModel?)/* or [ExampleModel]*/ -> Void)?) {
        super.FireRequestWithURLSession(url: /* url here */, methodType: /* method type here */, headers: /* headers here */) { (responseModel) in
            completion?(responseModel)
        }
    }

}

  • Usage

class MyLocationsController: UIViewController {

    // MARK: Properties
    // better to have in base class for the controller
    var exampleModelService: ExampleModelService = ExampleModelService()

    // MARK: Life Cycle Methods
    override func viewDidLoad() {
        super.viewDidLoad()
        exampleModelService.GetExampleModelList(completion: { [weak self] (response) in
            // model available here
        })
    }
}

like image 164
karem_gohar Avatar answered May 08 '26 19:05

karem_gohar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!