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`
}
}
}
@quiin
Copy link

quiin commented Jan 13, 2018

Hey, great gist; is there a chance you can include AlamoHelper code please as well as asDict() extension?

@swift2geek
Copy link

swift2geek commented Jan 24, 2018

p.s. Why do you need SwiftyJSON imported so on if you are using Codable??
It would be great to see how Codable works with CoreData and Alamofire...

@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