네트워크-EndPoint [후회 - SwiftUI 전환기(1)]

황제하·2022년 7월 20일
3
post-thumbnail

후회 - SwiftUI 전환기(1)

네트워크 EndPoint

네트워크 EndPoint를 생성하는 구조를 개선해봤다.

기존 네트워크 구조

HTTPService : HTTP 통신을 담당하는 타입

func fetch(_ path: APIPath, with coinSymbol: String) -> Observable<Data> {
    // 1. EndPoint 생성
    let path = "\(endPoint)/\(path.path)/\(coinSymbol)_\(path.paymentCurrency)"
        ...
}

1. EndPoint 생성

매개변수로 받은 APIPath는 열거형으로 Bithumb Public API 별 Case를 가지고 있다.
Case별 path만 가지고 있고, *특정 코인(CoinSymbol)은 fetch() 메서드의 매개변수로 따로 받아서 EndPoint를 생성하고 있다.

1-1. EndPoint 생성 개선점

*어떤 코인을 요청할 지는 fetch() 메서드의 매개변수로 따로 받아에서 개선점을 발견할 수 있다. 하나의 EndPoint를 만드는데 pathAPIPath 열거형에서, CoinSymbolfetch() 메서드의 매개변수로 받고 있다. 이는 코드의 응집도가 떨어진다 판단했다.

1-2. EndPoint 생성 개선

Alamofire의 URLRequestConvertible를 참고했다.

개선 후 코드

enum APIRouter {
    
    // MARK: - API Cases
    
    case ticker(coinSymbol: String)
    case transactionHistory(coinSymbol: String)
    case candlestick(coinSymbol: String)
    
    // MARK: - Base URL
    
    var baseURL: URL {
        return URL(string: "https://api.bithumb.com/public")!
    }
    
    // MARK: - Methods
    
    enum HTTPMethod: CustomStringConvertible {
        case get
        
        var description: String {
            switch self {
            case .get:
                return "GET"
            }
        }
    }
    
    var method: HTTPMethod {
        switch self {
        case .ticker, .transactionHistory, .candlestick:
            return .get
        }
    }
    
    // MARK: - Paths
    
    var path: String {
        switch self {
        case .ticker(let coinSymbol):
            return "/ticker/\(coinSymbol)_KRW"
        case .transactionHistory(let coinSymbol):
            return "/transaction_history/\(coinSymbol)_KRW"
        case .candlestick(let coinSymbol):
            return "/candlestick/\(coinSymbol)_KRW"
        }
    }
    
    // MARK: - asURLRequset
    
    func asURLRequest() -> URLRequest {
        let url = baseURL.appendingPathComponent(path)
        var urlRequset = URLRequest(url: url)
        urlRequset.httpMethod = "\(method)"
        
        return urlRequset
    }
}

개선된 HTTPService

func request(_ router: APIRouter) -> AnyPublisher<Data, HTTPError> 

// 사용 시 
// 비트코인 현재가를 조회하는 API
let bitcoinTicker = APIRouter.ticker("BTC")

request(bitcoinTicker)
    .sink {
       // ...
    }

APIRouter 열거형연산 프로퍼티(baseURL, method, path)를 만들고, Associated Values으로 CoinSymbol을 넘겨준다.
EndPoint를 구성하는 요소들을 하나의 타입에 모아둘 수 있다.
또, asURLRequset() -> URLRequest 메서드 내부에서 구성요소들로 URLRequest를 만든다.

마무리

이번 포스팅에서는 EndPoint 생성 및 개선했다.
위 포스팅처럼 하나의 APIRouter에서 여러 EndPoint를 관리하면 앱에서 사용하고 있는 EndPoint들을 한눈에 확인할 수 있는 장점이 있다.
하지만, EndPoint가 추가될수록 APIRouter가 비대해 질 수 있고, 기존 코드에 영향을 줄 수 있다고 판단된다.(단일책임 원칙, 개방폐쇄 원칙 위배....)

추후 EndPoint가 추가될 수 있는 점을 감안하면 구조는 다시 한번 개선해야겠다.

1개의 댓글

comment-user-thumbnail
2022년 7월 20일

답글 달기