SeSAC OOD 11/21 - Moya를 적용하자!

gaebokchi·2021년 11월 22일
0

OOD

목록 보기
3/7

오늘은 뭘할지 어디서부터 시작해야할지 고민하다가 서버통신 테스트 부터 해보기로 결정. 근데 서버통신도 어디서부터 시작해야하는지... 그냥 Alamofire만 사용할까 .. 하고 이 프로젝트 저 프로젝트 코드를 보다보니 Moya가 편해보였다. 코드만 봐도 뭘 의미하는지 바로 알 수 있어서 나중에 서버 더 붙여야하는 OOD도 유지보수가 더 쉬워질 것 같아서 Moya를 사용하기로 ㅎㅅㅎ

Moya Github

Moya

Moya는 Alamofire를 직접 호출해서 네트워크 추상화 레이어를 캡슐화 해주는 라이브러리 이다. 그래서 실제로 서버통신을 하는 역할이 아닌, 뭔가 보기 좋게 정리해주는? 라이브러리 라고 이해했는데..맞나
그래서 Alamofire은 URLSession을 추상화한다면, Moya는 URL, 매개 변수 등을 추상화 한다고 한다.

  • URLSession -> iOS에서 제공하는 HTTP를 통해 데이터를 주고받을 수 있도록 도와주는 API를 제공하는 Class

1. 모든 API를 열거형으로 설정하기

  • 우선 APIService.swift 라는 파일을 만들어서 사용되는 모든 API를 enum으로 설정해준다. 각 API에 필요한 파라미터들(토큰, 쿼리, 패스, 바디)도 각 케이스의 매개변수로 정의할 수 있다.
enum APITarget { // 토큰 쿼리 패스 바디 모두 입력
    case signup(email: String, password: String, nickname: String, exCycle: Int)
    case signin(email: String, password: String)
    case certiContentUpload(token: String, exTime: String, exIntensity: String, exEvalu: String, exComment: String, certiSport: String)
    case certiImageUpload(token: String, image: UIImage, certiId: Int)
    case certiByCal(token: String, date: String)
    case certiDetail(token: String, certiId: Int)
    case certiUpdate(token: String, exTime: String, exIntensity: String, exEvalu: String, exComment: String, certiSport: String, certiId: Int)
    case certiDelete(token: String, certiId: Int)
    case mypageAllCerti(token: String)
    case mypageInfo(token: String)
    case settingExCycle(token: String, exCycle: Int)
}

2. enum의 TargetType 채택

  • 방금 만들어준 API enum은 Moya의 TargetType 프로토콜을 필수로 채택해야 한다
extension APITarget: TargetType {
    var baseURL: URL {
        return URL(string: "http://[baeURL]")!
    }
    var path: String { // path에 들어갈 파라미터 넣어주기
        switch self {
        case .signup:
            return "/user/signup"
        case .signin:
            return "/user/signin"
        case .certiContentUpload:
            return "/certi"
        case .certiImageUpload(_, _, let certiId):
            return "/certi/image/\(certiId)"
        case .certiByCal:
            return "/certi"
        case .certiDetail(_, let certiId):
            return "/certi/detail/\(certiId)"
        case .certiUpdate:
            return "/certi"
        case .certiDelete(_, let certiId):
            return "/certi/\(certiId)"
        case .mypageAllCerti:
            return "/mypage"
        case .mypageInfo:
            return "/mypage/info"
        case .settingExCycle:
            return "/mypage/cycle"
        }
    }
    var method: Moya.Method { // 각 CRUD
        switch self {
        case .signup, .signin, .certiContentUpload, .certiImageUpload:
            return .post
        case .certiByCal, .certiDetail, .mypageAllCerti, .mypageInfo:
            return .get
        case .certiUpdate, .settingExCycle:
            return .put
        case .certiDelete:
            return .delete
        }
    }
    var sampleData: Data {
        return Data()
    }
    var task: Task { // 바디는 JSONEncoding.default, 쿼리가 들어가면 URLEncoding.queryString, 이미지는 .uploadMultipart
        switch self {
        case .certiDetail, .mypageAllCerti, .mypageInfo, .certiDelete:
            return .requestPlain
        case .certiByCal(_, let date): // 쿼리
            return .requestParameters(parameters: ["date": date], encoding: URLEncoding.queryString)
        case .signup(let email, let password, let nickname, let exCycle):
            return .requestParameters(parameters: ["email": email, "password": password, "nickname": nickname, "ex_cycle": exCycle], encoding: JSONEncoding.default)
        case .signin(let email, let password):
            return .requestParameters(parameters: ["email": email, "password": password], encoding: JSONEncoding.default)
        case .certiContentUpload(_, let exTime, let exIntensity, let exEvalu, let exComment, let certiSport):
            return .requestParameters(parameters: ["ex_time": exTime, "ex_intensity": exIntensity, "ex_evalu": exEvalu, "ex_comment": exComment, "certi_sport": certiSport], encoding: JSONEncoding.default)
        case .certiImageUpload(_, let image, _):
            let imageData = MultipartFormData(provider: .data(image.jpegData(compressionQuality: 1.0)!), name: "image", fileName: "jpeg", mimeType: "image/jpeg")
            return .uploadMultipart([imageData])
        case .certiUpdate(_, let exTime, let exIntensity, let exEvalu, let exComment, let certiSport, _):
            return .requestParameters(parameters: ["ex_time": exTime, "ex_intensity": exIntensity, "ex_evalu": exEvalu, "ex_comment": exComment, "certi_sport": certiSport], encoding: JSONEncoding.default)
        case .settingExCycle(_, let exCycle):
            return .requestParameters(parameters: ["ex_cycle": exCycle], encoding: JSONEncoding.default)
        }
    }
    var headers: [String : String]? {
        switch self {
        case .signup, .signin:
            return ["Content-Type": "application/json"]
        case .certiImageUpload(let token, _, _):
            return ["Content-Type": "multipart/form-data", "token": token]
        case .certiContentUpload(let token, _,_,_,_,_), .certiByCal(let token, _), .certiDetail(let token, _), .certiUpdate(let token, _,_,_,_,_,_), .certiDelete(let token, _), .mypageAllCerti(let token), .mypageInfo(let token), .settingExCycle(let token, _):
            return ["Content-Type" : "application/json", "token" : token]
        }
    }

baseURL : 서버 주소
path : 각 API 패스 저장 (Path variable 명시)
method : 각 API CRUD 타입 설정
task : 각 API 에서 필요한 파라미터들 설정
-> 바디를 함께 보내 요청해야 한다면 encoding: JSONEncoding.default
-> 쿼리가 필요하면 encoding: URLEncoding.queryString
-> 이미지는 return .uploadMultipart([MultipartFormData])
-> 아무것도 필요없으면 return .requestPlain
sampleData : 테스트용 data
headers : 각 API 헤더 지정 (Content-Type과 토큰)

3. Moya provider 사용

이번엔 APIService 구조체를 만들어주고 provider를 만들어준다.
target 이 api를 보기좋게 정리해놓은 enum 이었다면
provider 은 target의 api들을 가지고 request를 하기 위해 필요한 객체이다

struct APIService {
    static let shared = APIService()
    let provider = MoyaProvider<APITarget>()
  1. 제너릭 형태로 아까 만들어준 APITarget을 담아 MoyaProvider를 생성해준다
  2. 생성한 provider를 가지고 request 코드를 짜주면 끝! 아래는 오운동에서 날짜별 운동 게시물을 get 하기 위한 서버통신 코드이다. provider를 통해 request를 할 때 매개변수에 APITarget에서 정리해준 .certiByCal를 담아준 것을 볼 수 있음

+ 오늘한 것

- 폴더 정리 + plist 에서 라이트모드 고정 & font 설정 + color asset 추가 + launch screen + moya 공부

0개의 댓글