- Published on
π Swift - Moya
- Authors
- Name
- μ΄μ°½μ€
Moya
λͺ¨μΌκ° λ체 λͺ¨μΌ?
(μλ§ νκ΅μΈμ΄ μμ±ν λͺ¨μΌ κ²μλ¬Ό 80%λ μ΄κ±Έλ‘ μμν λ―β¦)
κ·Έλμ λͺ¨μΌλ λκΉμ?
Moyaλ enum
νμ
μ μ κ·Ήμ μΌλ‘ νμ©νμ¬ λ€νΈμν¬ μμ² λ μ΄μ΄λ₯Ό type-safe
νκ² λνν λ€νΈμνΉ λΌμ΄λΈλ¬λ¦¬μ
λλ€.
μ»΄νμΌ νμμ μλν¬μΈνΈ μ κ·Ό κ΄λ ¨ μλ¬λ₯Ό λμμ£ΌκΈ° λλ¬Έμ λμ± μμ νκ³ κ°νΈνκ² μ±μ λΉλν μ μλ€λ μ₯μ μ΄ μλ€κ³ ν΄μ!
Alamofireμμ κ΄κ³?
Swift μΈμ΄λ₯Ό μ²μ νμ΅ν λ URLSession
μ 곡λΆν λ€μ λ€νΈμν¬ κ΄λ ¨λ μ μ©ν λΌμ΄λΈλ¬λ¦¬κ° λ§λ€λ μ¬μ€μ μκ³ μ΄λ€ κ²μ΄ μλ μ΄ν΄λ³΄λ λκ° μμμ΅λλ€.
λͺ¨λκ° μκ³ μλ Alamofire
, Kingfisher
, Moya
λ±μ΄ μμμ£ ..
κ·Έ μ€μμ Kingfisher
λ μ΄λ―Έμ§ κ΄λ ¨ λΌμ΄λΈλ¬λ¦¬λ λ¨λ 건 Alamofire
μ Moya
μμ΅λλ€.
μ무κ²λ λͺ¨λ₯΄λ μ λ Moya
μ κ·μ¬μ΄ μ΄λ¦μ λλ € 무μμ 곡λΆλ₯Ό μμνλλ©μ£ ..
λ¬΄μ¨ λ§μΈμ§ νλλ μ΄ν΄νμ§ λͺ»νκ³ Alamofire
λ‘ νν΄νμλλ°μ.. λΉμ°νκ±°μμ΅λλ€.
Moya
μ λ€νΈμνΉμ μ¬μ€ Alamofire
λ₯Ό μ¬μ©νκΈ° λλ¬Έμ΄μ£ β¦!
Dependencyμ λ‘νλ λ°νμλκ² λ³΄μ΄μμ£ ..
κ°λ
λͺ¨μΌλ₯Ό μ΄ν΄νλ €λ©΄ μΈ κ°μ§ ν΅μ¬ μμλ₯Ό λ¨Όμ μμμΌν©λλ€.
Provider
MoyaProvider
κ°μ²΄λ‘ μ κ·Όν μ μλ λ©μΈ κ°μ²΄μ
λλ€.
λ€νΈμν¬ κ΄λ ¨ κΈ°λ₯μ μ¬μ©νκΈ° μν΄μλ 무쑰건 μ΄ MoyaProvider
κ°μ²΄λ₯Ό μμ±νκ±°λ μ£Όμ
λ°μμΌ ν©λλ€.
Target
APIλ₯Ό μ 곡νλ μλΉμ€λ₯Ό λΆλ₯΄λ λͺ μΉμ λλ€.
곡κ°λ μ€ν APIμΌ μλ μκ³ , νλ‘μ νΈ λ΄λΆμμ μ¬μ©λλ μλ²μ APIμΌ μλ μκ² μ£ .
μ΄ Target
μ TargetType
protocol
μ μ¬μ©ν΄μ μ μν΄μ€ μ μμ΅λλ€.
Endpoint
Endpoint
λ λ€νΈμνΉ μμ²μ μν΄ νμν μ 보λ€μ λ΄λ κ°μ²΄μ
λλ€.
HTTP λ©μλ, request body / header λ±μ μ 보λ€μ λ΄κ³ μκ³ , Target
λν MoyaProvider
μ μν΄ μ΄ Endpoint
λ‘ λ³νλμ΄ μ¬μ©λ©λλ€.
μ΄ Endpoint
λ₯Ό 컀μ€ν
νλ©΄ λͺ¨λ μ’
λ₯μ λ€νΈμνΉμ νμν λ°μ΄ν° 맡νμ μνν μ μλ€κ³ νλ€μ.
κΈ°μ΄
곡μ λ¬Έμ보λ€λ μ½λ°μ½μ μμ κ° μ¬μ보μ΄λκΉ μ½λ°μ½μ μμ λ‘ μ§νν΄λ³΄κ² μ΅λλ€.
public enum Marvel {
static private let publicKey = "PUBLIC_KEY"
static private let privateKey = "PRIVATE_KEY"
case comics
}
μ΄λ κ² enum
νμ
μΌλ‘ API μλΉμ€μ λν μ 보λ₯Ό λ£μ΄μ€ μ μμ΅λλ€.
case
μλ νμν API μλν¬μΈνΈλ§λ€ μ μν΄μ£Όλ©΄ λ©λλ€.
enum MyService {
case zen
case showUser(id: Int)
case createUser(firstName: String, lastName: String)
case updateUser(id: Int, firstName: String, lastName: String)
case showAccounts
}
μ΄λ κ²μ..!
μ°κ΄κ°μΌλ‘ λ£μ΄μ€ νλΌλ―Έν°λ€μ 리νμ€νΈμμ νλΌλ―Έν°κ° νμν κ²½μ° λ£μ΄μ£Όλ κ²μΌλ‘ νΈνκ² μ¬μ©ν μ μμ΅λλ€.
Target
μΌλ‘ μ¬μ©λ enum
μ λ°λμ TargetType
νλ‘ν μ½μ μ±νν΄μΌ νλ€κ³ νμμ£ ?
extension Marvel: TargetType {
public var baseURL: URL {
//
}
public var path: String {
//
}
public var method: Moya.Method {
//
}
public var sampleData: Data {
//
}
public var task: Moya.Task {
//
}
public var headers: [String : String]? {
//
}
}
νλ‘ν μ½μ μ±ννκ³ νμν νλ‘νΌν°λ€μ μλμΌλ‘ λ£μ΄μ£Όλ©΄ μμ κ°μ ννκ° λ©λλ€.
extension Marvel: TargetType {
public var baseURL: URL {
return URL(string: "https://gateway.marvel.com/v1/public")!
}
public var path: String {
switch self {
case .comics: return "/comics"
}
}
public var method: Moya.Method {
switch self {
case .comics: return .get
}
}
public var sampleData: Data {
return Data()
}
public var task: Moya.Task { // TODO: μλ§λ μ΅μ
μΌλ‘ λ³κ²½
return .requestPlain
}
public var headers: [String : String]? {
return ["Content-Type": "application/json"]
}
public var validationType: ValidationType {
return .successCodes
}
}
baseURL
API μλΉμ€μ baseURL
μ μ
λ ₯ν΄μ€λλ€.
path
baseURL
λ€μ λΆλ μμ² APIμ path
μ£Όμλ₯Ό μ
λ ₯ν΄μ€λλ€.
μμμ κ²½μ° μ 체 API μμ² μ£Όμλ https://gateway.marvel.com/v1/public/comics κ° λκ² μ£ !
method
path
μ λ§λ HTTPS ν΅μ λ©μλλ₯Ό λ°νν΄μ€λλ€.
ex) .get
, .delete
, .patch
λ±
sampleData
μ λ ν
μ€νΈλ₯Ό ν λλ μ€μ λ‘ μλ²κ° μμ κ²½μ°, μ΄ sampleData
λ‘ κ°μμ λ°μ΄ν°λ₯Ό λ΄μμ£Όλ©΄ ν΄λΉ λ°μ΄ν°λ₯Ό λ°νκ°μΌλ‘ λ°μμ΅λλ€.
νμνμ§ μμ κ²½μ° Data()
λ₯Ό λ°ννμ¬ λΉμ΄μλ λ°μ΄ν°λ₯Ό μ λ¬ν΄μ€λλ€!
task
μμ²μ νλΌλ―Έν°λ₯Ό ν¬ν¨νκ±°λ, λ°μ΄ν°λ₯Ό ν¬ν¨νμ¬ μμ²μ νλ λ±μ μ΅μ λ€μ μΆκ°μ μΌλ‘ μ 곡νμ¬ HTTP μμ²μ μ μ‘ν©λλ€.
APIκ° μꡬνλ μμμ΄λ μλ²μ μνλ±μ λ°λΌ λ무λ λ€μν κ²½μ°κ° μμΌλ―λ‘ μ°μ μλ¬΄λ° μ΅μ
μ λ£μ§ μλ .requestPlain
μ μ νν΄μ£Όμμ΅λλ€.
headers
HTTP ν€λλ₯Ό λ£μ΄μ€λλ€.
μμμμλ κ°μ₯ μμ£Ό μ°μ΄λ Content-Type: application/json
μ λ£μ΄μ£Όμμ΅λλ€. (JSON νμμ 컨ν
μΈ )
validationType
νμμ μΌλ‘ νμν νλͺ©μ μλμ§λ§, μμ£Ό μ°μ΄λ νλͺ©μ λλ€.
.successCodes
λ 200..<299
μ¬μ΄μ μλ΅ μ½λλ₯Ό λ°μΌλ©΄ ν΅μ μ μ±κ³΅νλ€κ³ μ²λ¦¬νλ caseμ
λλ€.
μ΄ Target
λ§ λ΄λ Moya
κ° λμΆ© μ΄λ€ λλμΌλ‘ μ°μ΄λ μ§ μ μ μμ κ² κ°λ€μ.
ν΅μ μ νμν λ°μ΄ν°λ€μ ν κ΅°λ° λͺ¨μλκ³ switch-case
λ₯Ό ν΅ν΄μ μ½κ² μμ² νλͺ©μ μ νν μ μμ κ² κ°μ΅λλ€.
https://developer.marvel.com/documentation/authorization
μ΄λ²μ μ¬μ©νλ λ§λΈ APIμ λ¬Έμλ₯Ό μ΄ν΄λ³΄κ³ , task
λΆλΆμ μ±μμ€μλ€.
Client-Side μ±μ μ¬μ μ μΈμ¦μ΄ λμ΄ μμ΄μΌ νλ€λκ΅°μ.
Server-Side λ°©μμΌλ‘ μ§νν΄μ€λλ€.
public var task: Task {
let ts = "\(Date().timeIntervalSince1970)"
let hash = (ts + Marvel.privateKey + Marvel.publicKey).md5
let authParams = ["apikey": Marvel.publicKey, "ts": ts, "hash": hash]
switch self {
case .comics:
return .requestParameters(
parameters: [
"format": "comic",
"formatType": "comic",
"orderBy": "-onsaleDate",
"dateDescriptor": "lastWeek",
"limit": 50] + authParams,
encoding: URLEncoding.default)
}
}
μ΄μ μ€μ λ‘ API requestλ₯Ό 보λ΄λ΄ μλ€.
let provider = MoyaProvider<Marvel>()
provider.request(.comics) { result in
switch result {
case .success(let response):
do {
print(try response.mapJSON())
} catch {
// error handling
}
case .failure:
// error handling
}
}
μμ κ°μ΄ μ§§κ³ κ°κ²°νκ² ν΅μ μμ²μ λ³΄λΌ μ μμ΅λλ€.
μμ²λκ² λ§μ λ°μ΄ν°λ€μ΄ λ€μ΄μ€λκ΅°μ..
μ΄ λ°μ΄ν°λ€μ κ°μΈκ³ View
μ μ μ©νλ λ΄μ©μ λ€λ₯Έ HTTP ν΅μ λ€κ³Ό κ°μ΅λλ€.
Moya
λ RxSwiftμλ μμ£Ό μ μ΄μΈλ¦½λλ€.
provider.rx.requestWithProgress(.zen).subscribe { event in
switch event {
case .next(let progressResponse):
if let response = progressResponse.response {
// do something with response
} else {
print("Progress: \(progressResponse.progress)")
}
case .error(let error):
// handle the error
default:
break
}
}
μ΄λ°μμΌλ‘ κΈ°λ³Έμ μΌλ‘ Rxνλ λμ΄μκ±°λ μ. (ν¨ν€μ§λ₯Ό μ€μΉν λ Moya/RxSwift
λ ν¨κ» μ€μΉν΄μ£Όμ΄μΌ ν©λλ€.)
λλ΅μ μΈ μ¬μ© λ°©λ²μ μμμΌλ μ€μ μ μ μ©ν΄λ³΄κΈ° μν΄ λ λ보λλ‘ νκ² μ΅λλ€.
References