Skip to content

Commit

Permalink
[Refactor]#71 UserAPI URL Session으로 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
wonniiii committed Mar 2, 2023
1 parent 78eb5b8 commit 377d5b8
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 83 deletions.
4 changes: 4 additions & 0 deletions Keyneez/Keyneez.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
0233C6FC296C8E4600A177E9 /* JellyDetailBottomSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0233C6FB296C8E4600A177E9 /* JellyDetailBottomSheetViewController.swift */; };
0233C6FE296C8F4A00A177E9 /* JellyDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0233C6FD296C8F4A00A177E9 /* JellyDetailView.swift */; };
023B559429655CD200FB2462 /* CGFloat+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023B559329655CD200FB2462 /* CGFloat+Extension.swift */; };
024EF5B429ABCE5A00085D0D /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024EF5B329ABCE5A00085D0D /* NetworkError.swift */; };
0250056E296DB58600DE08BE /* PhoneLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0250056D296DB58600DE08BE /* PhoneLoginViewController.swift */; };
02500573296DDF8F00DE08BE /* SignUpConstant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02500572296DDF8F00DE08BE /* SignUpConstant.swift */; };
02500575296DEF7F00DE08BE /* SimplePwdCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02500574296DEF7F00DE08BE /* SimplePwdCollectionViewCell.swift */; };
Expand Down Expand Up @@ -194,6 +195,7 @@
0233C6FB296C8E4600A177E9 /* JellyDetailBottomSheetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyDetailBottomSheetViewController.swift; sourceTree = "<group>"; };
0233C6FD296C8F4A00A177E9 /* JellyDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyDetailView.swift; sourceTree = "<group>"; };
023B559329655CD200FB2462 /* CGFloat+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+Extension.swift"; sourceTree = "<group>"; };
024EF5B329ABCE5A00085D0D /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = "<group>"; };
0250056D296DB58600DE08BE /* PhoneLoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneLoginViewController.swift; sourceTree = "<group>"; };
02500572296DDF8F00DE08BE /* SignUpConstant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpConstant.swift; sourceTree = "<group>"; };
02500574296DEF7F00DE08BE /* SimplePwdCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplePwdCollectionViewCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -736,6 +738,7 @@
B14D10B92959CC340004946F /* NetworkLayer */ = {
isa = PBXGroup;
children = (
024EF5B329ABCE5A00085D0D /* NetworkError.swift */,
B1A80379296E9D680007DDD9 /* Encodable.swift */,
B1A8037B296E9DB60007DDD9 /* NetworkLoggerPlugin.swift */,
B8FC6639296F22EA00AEE9C3 /* ContentAPI.swift */,
Expand Down Expand Up @@ -1292,6 +1295,7 @@
022CB224296A2B370084DEF5 /* SignUpContentModel.swift in Sources */,
B8C02F052962F5D4005612CE /* SettingViewController.swift in Sources */,
B1A80363296DA9A40007DDD9 /* IDIssuedViewActionables.swift in Sources */,
024EF5B429ABCE5A00085D0D /* NetworkError.swift in Sources */,
0233C6F8296C07A300A177E9 /* JellyProductCollectionViewCell.swift in Sources */,
B18B60D2296552DA00AF14F5 /* NiblessViewController.swift in Sources */,
B10AAD64296967F300AB8475 /* BenefitCollectionViewCell.swift in Sources */,
Expand Down
32 changes: 32 additions & 0 deletions Keyneez/Keyneez/Global/NetworkLayer/NetworkError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// NetworkError.swift
// Keyneez
//
// Created by 최효원 on 2023/02/27.
//

import Foundation

enum NetworkError: LocalizedError {
case unknownError
case invalidStatusCode(Int)
case invalidResponse(Error)
case components
case badRequest(Error)
case parsing(Error)
case emptyData
case decodeError

var errorDescription: String? {
switch self {
case .unknownError: return "알수 없는 에러입니다."
case .invalidStatusCode: return "status코드가 200~299가 아닙니다."
case .invalidResponse: return "잘못된 응답입니다."
case .components: return "components를 생성 에러가 발생했습니다."
case .badRequest: return "URL request 관련 에러가 발생했습니다."
case .parsing: return "데이터 parsing 중에 에러가 발생했습니다."
case .emptyData: return "data가 비어있습니다."
case .decodeError: return "decode 에러가 발생했습니다."
}
}
}
103 changes: 60 additions & 43 deletions Keyneez/Keyneez/Global/NetworkLayer/UserAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//

import Foundation
import Moya

enum UserAPIError: LocalizedError {
case encodingError
Expand All @@ -23,7 +22,7 @@ enum UserAPI {
case patchUserWithOCRTeenID(token: String, param: UserCheckYouthIDRequestDto)
}

extension UserAPI: TargetType {
extension UserAPI {

var baseURL: URL {
return URL(string: "http://15.165.186.200:3000")!
Expand All @@ -33,71 +32,89 @@ extension UserAPI: TargetType {
switch self {
case .getUserInfo:
return URLConstant.user
case .postUserInfo, .patchUserPickInfo:
case .postUserInfo,
.patchUserPickInfo:
return "/user/signup"
case .patchUserPwdInfo, .postPwdFetch:
case .patchUserPwdInfo,
.postPwdFetch:
return "/user/signup/pw"
case .postUserLoginInfo:
return "/user/signin"
case .patchUserWithOCRSchoolID, .patchUserWithOCRTeenID, .getUserInfo:
case .patchUserWithOCRSchoolID,
.patchUserWithOCRTeenID,
.getUserInfo:
return "/user"
default:
return ""
}
}

var method: Moya.Method {
var method: String {
switch self {
case .postUserInfo:
return .post
case .patchUserPickInfo:
return .patch
case .patchUserPwdInfo, .patchUserWithOCRTeenID, .patchUserWithOCRSchoolID:
return .patch
case .postPwdFetch:
return .post
case .postUserLoginInfo:
return .post
return "POST"
case .patchUserPickInfo,
.patchUserPwdInfo,
.patchUserWithOCRTeenID,
.patchUserWithOCRSchoolID:
return "PATCH"
case .postPwdFetch,
.postUserLoginInfo:
return "POST"
case .getUserInfo:
return .get
return "GET"
}
}

var headers: [String: String]? {
switch self {
case .postUserInfo,
.postUserLoginInfo:
return ["Content-Type": "application/json"]
case .patchUserPickInfo(let token, _),
.patchUserPwdInfo(let token, _),
.postPwdFetch(let token, _),
.getUserInfo(let token),
.patchUserWithOCRTeenID(let token, _),
.patchUserWithOCRSchoolID(let token, _):
return ["Content-Type": "application/json", "Authorization": token]
default:
return nil
}
}

var task: Moya.Task {
private func body() -> [String: Any]? {
switch self {
case .postUserInfo(let param):
return .requestParameters(parameters: try! param.asParameter(), encoding: JSONEncoding.default)
return try? param.asParameter()
case .patchUserPickInfo(_, let param):
return .requestParameters(parameters: try! param.asParameter(), encoding: JSONEncoding.default)
case .patchUserPwdInfo(_, let param):
return .requestParameters(parameters: try! param.asParameter(), encoding: JSONEncoding.default)
return try? param.asParameter()
case .patchUserPwdInfo(_, param: let param):
return try? param.asParameter()
case .postPwdFetch(_, param: let param):
return .requestParameters(parameters: try! param.asParameter(), encoding: JSONEncoding.default)
case .postUserLoginInfo(let param):
return .requestParameters(parameters: try! param.asParameter(), encoding: JSONEncoding.default)
return try? param.asParameter()
case .postUserLoginInfo(param: let param):
return try? param.asParameter()
case .patchUserWithOCRSchoolID(_, param: let param):
return try? param.asParameter()
case .patchUserWithOCRTeenID(token: let token, param: let param):
return try? param.asParameter()
case .getUserInfo:
return .requestPlain
case .patchUserWithOCRSchoolID(_, let param):
return .requestParameters(parameters: try! param.asParameter(), encoding: JSONEncoding.default)
case .patchUserWithOCRTeenID(_, let param):
return .requestParameters(parameters: try! param.asParameter(), encoding: JSONEncoding.default)
return nil
}
}

private var vaildationType: Moya.ValidationType {
return .successAndRedirectCodes
}

var headers: [String: String]? {
switch self {
case .postUserInfo, .postUserLoginInfo:
return ["Content-Type": "application/json"]
case .patchUserPickInfo(let token, _), .patchUserPwdInfo(let token, _),
.postPwdFetch(let token, _), .getUserInfo(let token), .patchUserWithOCRTeenID(let token, _), .patchUserWithOCRSchoolID(let token, _):
return ["Content-Type": "application/json", "Authorization": token]
default:
return nil
// Url Request setting 함수
func asURLRequest() -> URLRequest {
let url = baseURL.appendingPathComponent(path)
var request = URLRequest(url: url)
request.httpMethod = method
request.allHTTPHeaderFields = headers

if let param = body() {
let jsonData = try? JSONSerialization.data(withJSONObject: param)
request.httpBody = jsonData
}
return request
}

}
82 changes: 42 additions & 40 deletions Keyneez/Keyneez/Global/NetworkLayer/UserAPIProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Created by Jung peter on 1/11/23.
//

import Moya
import Foundation

enum DecodeError: Error {
Expand All @@ -21,71 +20,74 @@ struct UserInfo: Codable {
final class UserAPIProvider {

static let shared: UserAPIProvider = .init()
let userProvider = MoyaProvider<UserAPI>(plugins: [NetworkLoggerPlugin(verbose: true)])

private init() { }

func postUserInfo(param: ProductDanalRequestDto, completion: @escaping (Result<ProductDanalResponseDto?, Error>) -> Void) {
let target = UserAPI.postUserInfo(param: param)
responseFrom(target, modelType: ProductDanalResponseDto.self, completion: completion)
makeRequest(UserAPI.postUserInfo(param: param), modelType: ProductDanalResponseDto.self, completion: completion)
}

func patchUserInfo(token: String, param: ProductJellyRequstDto, completion: @escaping (Result<ProductJellyResponseDto?, Error>) -> Void) {
let target = UserAPI.patchUserPickInfo(token: token, param: param)
responseFrom(target, modelType: ProductJellyResponseDto.self, completion: completion)
makeRequest(UserAPI.patchUserPickInfo(token: token, param: param), modelType: ProductJellyResponseDto.self, completion: completion)
}

func patchPwdInfo(token: String, param: ProductPwdRequestDto, completion: @escaping (Result<ProductPwdResponseDto?, Error>) -> Void) {
let target = UserAPI.patchUserPwdInfo(token: token, param: param)
responseFrom(target, modelType: ProductPwdResponseDto.self, completion: completion)
makeRequest(UserAPI.patchUserPwdInfo(token: token, param: param), modelType: ProductPwdResponseDto.self, completion: completion)
}

func postLoginInfo(param: LoginRequestDto, completion: @escaping (Result<LoginResponseDto?, Error>) -> Void) {
let target = UserAPI.postUserLoginInfo(param: param)
responseFrom(target, modelType: LoginResponseDto.self, completion: completion)
makeRequest(UserAPI.postUserLoginInfo(param: param), modelType: LoginResponseDto.self, completion: completion)
}

func patchInfoWithStudentIDOCR(token: String, param: UserCheckStudentIDRequestDto, completion: @escaping(Result<EditUserResponseDto?, Error>) -> Void) {
let target = UserAPI.patchUserWithOCRSchoolID(token: token, param: param)
responseFrom(target, modelType: EditUserResponseDto.self, completion: completion)
makeRequest(UserAPI.patchUserWithOCRSchoolID(token: token, param: param), modelType: EditUserResponseDto.self, completion: completion)
}

func patchInfoWithTeenIDOCR(token: String, param: UserCheckYouthIDRequestDto, completion: @escaping(Result<EditUserResponseDto?, Error>) -> Void) {
let target = UserAPI.patchUserWithOCRTeenID(token: token, param: param)
responseFrom(target, modelType: EditUserResponseDto.self, completion: completion)
makeRequest(UserAPI.patchUserWithOCRTeenID(token: token, param: param), modelType: EditUserResponseDto.self, completion: completion)
}

func getUserInfo(token: String, completion: @escaping (Result<UserInquiryResponseDto?, Error>) -> Void) {
let target = UserAPI.getUserInfo(token: token)
responseFrom(target, modelType: UserInquiryResponseDto.self, completion: completion)
makeRequest(UserAPI.getUserInfo(token: token), modelType: UserInquiryResponseDto.self, completion: completion)
}
}

extension UserAPIProvider {

func responseFrom<T: Codable>(_ target: UserAPI, modelType: T.Type, completion: @escaping (Result<T?, Error>) -> Void) {
userProvider.request(target) { result in
self.process(type: modelType, result: result, completion: completion)
}
}

func process<T: Codable>(
type: T.Type,
result: Result<Response, MoyaError>,
completion: @escaping (Result<T?, Error>) -> Void
) {
switch result {
case .success(let response):
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
if let data = try? decoder.decode(GenericResponse<T>.self, from: response.data), data.status >= 200 && data.status < 400 {
let body = data.data
completion(.success(body as? T))
} else {
completion(.failure(DecodeError.decodeError))

func makeRequest<T: Codable>(_ target: UserAPI, modelType: T.Type, completion: @escaping (Result<T?, Error>) -> Void) {
//세션 생성
let session = URLSession.shared
//task 지정
let task = session.dataTask(with: target.asURLRequest()) { data, response, error in

//에러 처리 - Response
if let error = error {
completion(.failure(error))
return
}

guard let httpResponse = response as? HTTPURLResponse else {
completion(.failure(NetworkError.invalidResponse as! Error))
return
}

let statusCode = httpResponse.statusCode
guard (200..<300).contains(statusCode) else {
completion(.failure(NetworkError.invalidStatusCode(statusCode)))
return
}

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

if let data = data, let response = try? decoder.decode(GenericResponse<T>.self, from: data) {
let body = response.data
completion(.success(body as? T))
} else {
completion(.failure(DecodeError.decodeError))
}
}
case .failure(let error):
completion(.failure(error))
task.resume()
}
}
}

0 comments on commit 377d5b8

Please sign in to comment.