Skip to content

Instantly share code, notes, and snippets.

@jdmcd
Last active June 19, 2020 07:37
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save jdmcd/7126d39220b88500fcb8f9f6f8f3b30b to your computer and use it in GitHub Desktop.
Save jdmcd/7126d39220b88500fcb8f9f6f8f3b30b to your computer and use it in GitHub Desktop.
Alamofire + Codable
class API {
static let apiKey = "test"
static let baseUrl = ""
enum Endpoint {
case login
case register
var endpoint: String {
switch self {
case .login:
return "login"
case .register:
return "register"
}
}
}
static func createUrl(endpoint: Endpoint) -> String {
return "\(API.baseUrl)\(endpoint.endpoint)"
}
}
import Foundation
import Alamofire
protocol APIRequestRepresentable {
associatedtype CodableType: APIModelCodable
static var method: Alamofire.HTTPMethod { get set }
static var endpoint: API.Endpoint { get set }
static func request(parameters: Codable?, completion: @escaping (_ object: CodableType?, _ error: ErrorResponse?) -> Void)
static func defaultHeaderObject() -> DefaultHeader
static func defaultHeader() -> HTTPHeaders
static func tokenHeader(token: String) -> HTTPHeaders
static func url() -> String
}
extension APIRequestRepresentable {
static func defaultHeaderObject() -> DefaultHeader {
return DefaultHeader(contentType: "application/json; charset=utf-8", apiKey: API.apiKey)
}
static func defaultHeader() -> HTTPHeaders {
return defaultHeaderObject().asStringValueDictionary()
}
static func tokenHeader(token: String) -> HTTPHeaders {
return TokenHeader(defaultHeader: defaultHeaderObject(), token: "Bearer \(token)").asStringValueDictionary()
}
static func url() -> String {
return API.createUrl(endpoint: endpoint)
}
static func request(parameters: Codable?, completion: @escaping (_ object: CodableType?, _ error: ErrorResponse?) -> Void) {
AlamoHelper.manager.request(
url(),
method: method,
parameters: parameters?.asDictionary(),
encoding: JSONEncoding.default,
headers: defaultHeader()).responseJSON { response in
//each response should have a status code and a json value
guard let statusCode = response.response?.statusCode else {
completion(nil, ErrorResponse(reason: "Could not get status code"))
return
}
guard let jsonValue = response.result.value else {
completion(nil, ErrorResponse(reason: "Could not get JSON value"))
return
}
guard let data = try? JSONSerialization.data(withJSONObject: jsonValue) else {
completion(nil, ErrorResponse(reason: "Could not parse data"))
return
}
if 200...299 ~= statusCode {
//success
completion(CodableType.from(data: data), nil)
} else {
//error - we need a JSONDecoder here because `ErrorResponse` does not conform to APIModel
completion(nil, try? JSONDecoder().decode(ErrorResponse.self, from: data))
}
}
}
}
import Foundation
import Alamofire
import SwiftyJSON
struct LoginRequest: APIRequestRepresentable {
typealias CodableType = User
static var method: Alamofire.HTTPMethod = .post
static var endpoint: API.Endpoint = .login
}
import Foundation
protocol APIModel {
var id: Int { get set }
}
typealias APIModelCodable = APIModel & Codable
extension APIModel where Self: Codable {
static func from(json: String, using encoding: String.Encoding = .utf8) -> Self? {
guard let data = json.data(using: encoding) else { return nil }
return from(data: data)
}
static func from(data: Data) -> Self? {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try? decoder.decode(Self.self, from: data)
}
var jsonData: Data? {
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
return try? encoder.encode(self)
}
var jsonString: String? {
guard let data = self.jsonData else { return nil }
return String(data: data, encoding: .utf8)
}
}
import Foundation
struct User: APIModelCodable {
var id: Int
var name: String
var email: String
var admin: Bool
var token: String
}
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let loginRequest = Login(email: "email@email.com", password: "password")
LoginRequest.request(parameters: loginRequest) { (user, error) in
//`user` is of type `User` thanks to the typealias declaration in `LoginRequest`
}
}
}
@Nanixel
Copy link

Nanixel commented Jun 22, 2018

How can this be adapted to return a collection of models? For example if you were to get all users for instance?

@dushansapu
Copy link

AlamoHelper and DefaultHeader are missing..

@atov
Copy link

atov commented Aug 31, 2018

great gist , but like the others will search for the AlamoHelper idea

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment