Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- SWIFT
- MVVM
- swift documentation
- ios
- Clean Code
- 스위프트
- 애니메이션
- RxCocoa
- 리펙터링
- clean architecture
- 리펙토링
- UICollectionView
- combine
- Protocol
- rxswift
- ribs
- map
- tableView
- Observable
- uitableview
- Human interface guide
- Refactoring
- 리팩토링
- UITextView
- 클린 코드
- swiftUI
- Xcode
- uiscrollview
- HIG
- collectionview
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[Moya] Moya프레임 워크 (RESTFul API) 본문
* 사용 방법(secret): ios-development.tistory.com/267
Moya프레임워크
* 실무적으로 쓰는 형태는 여기 참고: ios-development.tistory.com/219
- Alamofire 프레임워크가 내부적으로 포함 (podfile.lock파일에서 확인)
- Alamofire가 있지만 굳이 Moya프레임워크를 사용하는 이유
- Alamofire를 사용하면, URL과 같은 것을 사용할 때 request에 넣어주어야 하며(Network Layer접근), 템플릿이 갖추어 지지 않아서 재사용에 유리하지 않은 구조
- Moya프레임 워크를 사용하면 Moya에서 Network layer를 템플릿화 해놓고 사용하는 입장인 App에서는 request, response만 처리하면 됨
Moya 프레임워크 의존성
pod 'Moya/RxSwift'
APIEnvironment정의 : 각 base url정의 (qa, staging, production)
//
// NetworkManager.swift
// Domain
//
// Created by 김종권 on 2020/10/24.
//
import Foundation
import Moya
enum APIEnvironment: String {
case qa = "https://qa.com"
case staging = "https://staging.com"
case production = "https://production.com"
}
struct NetworkManager {
fileprivate let provider = MoyaProvider<AppStatusTarget>()
static let environment: APIEnvironment = .qa
}
Request, Response모델 정의 (Response에는 json -> struct 매핑하기 쉽게 해주는 Codable사용)
//
// MyStatusModel.swift
// Domain
//
// Created by 김종권 on 2020/10/24.
//
import Foundation
import UIKit
public struct MyStatusModel: Codable {
public struct Request {
}
public struct Response: Codable {
public let requireVersion: String
public let latestVersion: String
}
}
TargetType정의: network템플릿 작성
//
// MyStatusTarget.swift
// Domain
//
// Created by 김종권 on 2020/10/24.
//
import Foundation
import Moya
public enum MyStatusTarget {
case version
}
extension MyStatusTarget: TargetType {
public var baseURL: URL {
guard let url = URL(string: NetworkManager.environment.rawValue) else {
fatalError("fatal error - invalid url")
}
return url
}
public var path: String {
switch self {
case .version:
return "version"
}
}
public var method: Moya.Method {
switch self {
case .version:
return .get
}
}
public var sampleData: Data {
switch self {
case .version:
return "{\"latestVersion\":\"1.1.0\",\"minimumVersion\":\"1.0.0\"}".data(using: .utf8)!
}
}
public var task: Task {
switch self {
case .version:
return .requestPlain
}
}
public var headers: [String: String]? {
return ["Content-Type": "application/json"]
}
public var validationType: ValidationType {
return .successCodes
}
}
Provider를 wrapping한 클래스 생성
//
// MyStatusAPI.swift
// Domain
//
// Created by 김종권 on 2020/10/24.
//
import Foundation
import Moya
import RxSwift
public class MyStatusAPI {
let bag = DisposeBag()
lazy var provider: MoyaProvider<MyStatusTarget> = {
if configurations.useStub {
return .init(stubClosure: MoyaProvider.delayedStub(0.5))
} else {
return .init()
}
}()
public init() { }
public func version(completion: @escaping (Result<MyStatusModel.Response, Error>) -> Void) {
provider.rx
.request(.version)
.filterSuccessfulStatusCodes()
.map(MyStatusModel.Response.self)
.subscribe { result in
switch result {
case .success(let response):
completion(.success(response))
case .error(let error):
completion(.failure(error))
}
}.disposed(by: bag)
}
}
제네릭하여, result를 처리하는 방법
- MyStatusAPI의 다른 provider에서도, request를 json -> struct로 바꿀 때 재사용 가능하므로 제네릭으로 선언하는게 유리
//
// MyStatusAPI.swift
// Domain
//
// Created by 김종권 on 2020/10/24.
//
import Foundation
import Moya
import RxSwift
enum DecodeError: Error {
case decodeError
}
public class MyStatusAPI {
let bag = DisposeBag()
lazy var provider: MoyaProvider<MyStatusTarget> = {
if configurations.useStub {
return .init(stubClosure: MoyaProvider.delayedStub(0.5))
} else {
return .init()
}
}()
public init() { }
public func version(completion: @escaping (Result<MyStatusModel.Response, Error>) -> Void) {
provider.request(.version) { result in
self.process(type: AppVersionResponse.self, result: result, completion: completion)
}
}
}
extension MyStatusAPI {
func process<T: Codable, E>(
type: T.Type,
result: Result<Response, MoyaError>,
completion: @escaping (Result<E, Error>) -> Void
) {
switch result {
case .success(let response):
if let data = try? JSONDecoder().decode(type, from: response.data) {
completion(.success(data as! E))
} else {
completion(.failure(DecodeError.decodeError))
}
case .failure(let error):
completion(.failure(error))
}
}
}
사용하는 쪽
provider.rx.request(.version)
.filterSuccessfulStatusCodes()
.map(MyStatusModel.Response.self)
.subscribe { (event) in
switch event {
case .success(let response):
print(response)
case .error(let error):
print(error)
}
}.disposed(by: bag)
정보 참고: github.com/Moya/Moya
'REST API' 카테고리의 다른 글
Postman으로 mock서버 구축하기 (REST API) (0) | 2020.10.23 |
---|
Comments