Skip to content

Instantly share code, notes, and snippets.

@J0onYEong
Last active July 3, 2024 05:07
Show Gist options
  • Save J0onYEong/fbdba77437c87ad7404a164855f967c0 to your computer and use it in GitHub Desktop.
Save J0onYEong/fbdba77437c87ad7404a164855f967c0 to your computer and use it in GitHub Desktop.
Moya라이브러리 연습 코드
//
// Requesting.swift
// MoyaPractice
//
// Created by choijunios on 7/3/24.
//
import Foundation
import Moya
import RxMoya
import Alamofire
import RxSwift
enum APIType {
case users
case gists
}
protocol BaseAPI: TargetType {
var apiType: APIType { get }
}
extension BaseAPI {
var baseURL: URL {
let base = "https://api.github.com"
switch apiType {
case .users:
return URL(string: base + "/users")!
case .gists:
return URL(string: base + "/gists")!
}
}
var path: String {
switch apiType {
case .users:
"users"
case .gists:
"gists"
}
}
/// Default header
var headers: [String : String]? {
return ["Content-Type": "application/json"]
}
}
// MARK: Concrete
enum UserAPI {
case junyeong
case alice
}
extension UserAPI: BaseAPI {
var apiType: APIType { .users }
var path: String {
switch self {
case .junyeong:
return "junyeong"
case .alice:
return "alice"
}
}
var method: Moya.Method {
switch self {
case .junyeong:
return .get
case .alice:
return .get
}
}
/// body Data, Request Parameter등이 들어감
/// 바디데이타와 쿼리 데이터를 하나의 타입으로 동시에 지정가능
var task: Moya.Task {
.requestPlain
}
}
struct UserDTO: Decodable {
let login: String
enum CodingKeys: String, CodingKey {
case login
}
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.login = try container.decode(String.self, forKey: .login)
}
}
// MARK: Service
class BaseService<TagetAPI: BaseAPI> {
lazy var provider = self.defaultProvider
private lazy var defaultProvider: MoyaProvider<TagetAPI> = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 10
configuration.timeoutIntervalForResource = 10
configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
let session = Session(configuration: configuration)
let provider = MoyaProvider<TagetAPI>(
// endpointClosure: endpointClosure,
session: session
)
return provider
}()
private let endpointClosure = { (target: TagetAPI) -> Endpoint in
let url = target.baseURL.appendingPathComponent(target.path).absoluteString
var endpoint: Endpoint = Endpoint(
url: url,
sampleResponseClosure: {.networkResponse(200, target.sampleData)},
method: target.method,
task: target.task,
httpHeaderFields: target.headers)
return endpoint
}
}
extension BaseService {
func requestDecodable<T: Decodable>(api: TagetAPI) -> Single<T> {
Single<T>.create { single in
let cancellable = self.provider.request(api) { result in
switch result {
case .success(let response):
do {
let decoded = try response.map(T.self)
single(.success(decoded))
} catch {
single(.failure(error))
}
case .failure(let error):
single(.failure(error))
}
}
return Disposables.create {
cancellable.cancel()
}
}
}
func requestDecodableRx<T: Decodable>(api: TagetAPI) -> Single<T> {
self.provider.rx.request(api)
.map(T.self)
}
func requestRxProgress<T: Decodable>(api: TagetAPI) -> Single<T> {
Single<T>.create { single in
self.provider.rx
.requestWithProgress(api)
.subscribe(onNext: { response in
print("progress: \(response.progress)")
if let result = response.response {
do {
let decoded = try result.map(T.self)
single(.success(decoded))
} catch {
single(.failure(error))
}
}
})
}
}
}
class UserService: BaseService<UserAPI> {
deinit {
print("UserService deinit")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment