Skip to content

요셉_네트워크 HTTP통신 기본 요소, Moya 네트워크 예제

Joseph Cha edited this page May 2, 2023 · 2 revisions

HTTP 통신 기본 요소

Header

  • HTTP 본문(body) 및 Request/Response에 대한 정보를 포함함
  • HTTP 헤더는 클라이언트와 서버가 요청 또는 응답으로 부가적인 정보를 전송할 수 있도록 해줌

Method

  • 클라이언트가 웹서버에게 요청하는 목적 및 그 종류를 알리는 수단

  • 종류

    • GET : 리소스 획득, URL(URI) 형식으로 웹서버측 리소스(데이터)를 요청
    • HEAD : 메세지헤더(문서정보) 취득
      • GET과 비슷하나, 실제 문서를 요청하는 것이 아니라, 문서정보를 요청, 이에따라HTTP 응답 메세지에 본문(Body)이 없이HTTP 헤더정보 만을 보냄
    • POST : 내용 전송 (파일 전송도 가능)
      • 요청 데이터를 HTTP Body에 담아 웹서버로 전송함
    • PUT : 내용 갱신 위주(파일 전송도 가능)
      • POST처럼 정보를 서버로 제출하는 것으로 형식은 동일하나, 갱신 위주임
    • DELETE : 파일 삭제
      • 웹 리소스를 제거
    • OPTIONS : 웹서버측 제공 메소드에 대한 질의
    • TRACE : 요청 리소스가 수신되는 경로를 보여줌(거의 사용 안함)
    • CONNET : 프록시 서버와 같은 중간 서버 경유(거의 사용 안함)

    GET, POST 2개 또는 OPTIONS를 포함 3개만을 허용하는 경우가 보안상의 이유로 일반적임

Body

  • 메세지 바디(메세지 본문)를 통해 '표현 데이터' 전달
  • 메세지 본문 = 페이로드
  • '표현' : 요청 & 응답에서 전달할 실제 데이터
  • 표현 헤더는 표현 데이터를 해석할 수 있는 정보 제공

Query String

  • Query String은 지정된 매개 변수에 값을 할당하는 URL의 일부
  • 클라이언트에 의해 기본 URL뒤에 덧붙여서 추가적인 정보를 서버측에 전달하는것. 클라이언트가 어떤 특정 리소스에 접근하고 싶어하는지 정보를 담음
  • 정해진 엔드포인트 주소 이후에 ?를 쓰는것으로 쿼리스트링이 시작함, parameter=value(=로 Key와 Value 구분)로 필요한 파라미터의 값을 적음 (파라미터가 여러개일 경우 &를 붙여 여러개의 파라미터를 넘길 수 있음)

Moya

  • Alamofire를 한번 더 추상화해서, 네트워크 계층을 템플릿화하여 재사용성, 가독성을 높여 개발자는 오로지 Response와 Request에만 신경 쓸수 있도록해 생상선을 높일 수 있음

moya

  • 기존 구조의 문제점으로 크게 3가지를 제시하고 있음
    • Makes it hard to write new apps (“where do I begin?”)

      어디서 부터 시작할지 시작의 어려움

    • Makes it hard to maintain existing apps (“oh my god, this mess…”)

      유지보수의 어려움

    • Makes it hard to write unit tests (“how do I do this again?”)

      유닛 테스트 작성의 어려움

사용법

  • Enum을 통해 API 목록 작성

    enum UserAPI {
        case LogIn(oAuthProvider : OAuthProvider, accessToken : String)
        case refreshToken
    }
  • TargetType 작성

    • 작성한 API목록에 TargetType 프로토콜을 채택해 API별로 Request에 필요한 것들을 지정할 수 있음

    baseURL : Server base URL 지정

    path : API Path 지정

    method : HTTP Method 지정

    sampleData : Mock Data for Test

    task : Parameters for request 지정

    validationType : 허용할 response 정의 - [validationType 참고](https://github.com/Moya/Moya/blob/development/Sources/Moya/ValidationType.swift)기존 `Alamofire 의 .validate() 처럼 리스폰스의 StatusCode` 에 따라 성공 유무를 판단

    headers : HTTP headers 적용: 기존의 인터셉터의 Adapter 역할을 할 수 있습니다. (ex. 헤더에 JWT 값 넣기)

    extension UserAPI : TargetType {
        var baseURL: URL { URL(string: ServiceAPI.baseURL)! }
        
        var path: String {
            switch self {
                case .LogIn(oAuthProvider: let type, accessToken: _) : return "/login/oauth/" + type.rawValue
                case .refreshToken : return "/token"
            }
        }
        
        var method: Moya.Method {
            switch self {
                case .LogIn(oAuthProvider: _, accessToken: _) : return .post
                case .refreshToken : return .get
            }
        }
        
        // var sampleData: Data { ... }
        
        var task: Task {
            switch self {
                case .LogIn(oAuthProvider: _, accessToken: let accessToken) :
                    let params : [String: String] = [ "accessToken" : accessToken ]
                    return .requestParameters(parameters: params, encoding: URLEncoding.default )
                case .refreshToken : return .requestPlain
            }
        }
        
        var headers: [String : String]? {
            switch self {
                case .refreshToken :
                    guard let userInfo = UserService.shared.userInfo else { return [ "Content-type": "application/json" ] }
                    return [ "Content-type": "application/json", "X-AUTH-TOKEN" : userInfo.token.tokenType + " " + userInfo.token.accessToken ]
                case .LogIn(oAuthProvider: _, accessToken: _) : return nil // [ "Content-type": "application/json" ]
            }
        }
        
        var validationType: ValidationType { .successCodes }
    }
  • Moya Provider 생성

    private let provider = MoyaProvider<UserAPI>()
    • 네트워크 요청을 수행할 Moya Provider 인스턴스를 생성
    • 제네릭 타입으로 TargetType 프로토콜을 준수하는 Enum(API 목록) 을 받고 있음
  • 네트워크 요청 / 처리 - Moya

    • Provider를 통해 Request가 가능한데, Request 메소드의 파라미터로 TargetType를 준수하는 API목록의 case를 전달함
    • 반환되는 response 는 Result<Response, MoyaError> 형태
    provider.request(.LogIn(oAuthProvider: .Kakao, accessToken: accessToken)) { response in
        switch response {
            case .success(let result) :
                guard let data = try? result.map(DataResponse<OAuthLoginResponse>.self) else { return }
                print(data)
            case .failure(let err):
                print(err.localizedDescription)
        }
    }

장점

  • Compile-time checking for correct API endpoint accesses

    컴파일시 API 엔드 포인트가 올바른지 체크

  • Lets you define a clear usage of different endpoints with associated enum values.

    Enum을 이용해서 언제, 어디에 사용될지 안전하게 (type-safe) 정의

  • Treats test stubs as first-class citizens so unit testing is super-easy.

    유닛 테스트를 용이하게 만듦.