Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

일반 회원가입 Username 확인 API, 인증 코드 전송 API, 인증 코드 검증 API 연동 #170

Open
wants to merge 13 commits into
base: feature/network_tony
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 66 additions & 2 deletions Project_Timer.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions Project_Timer/Data/API/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Foundation
import Moya

extension TargetType {
/// Request 구조체 -> dictionary 반환
static func parameters(from encodable: Encodable) -> [String: Any] {
let encoder = JSONEncoder()
guard let data = try? encoder.encode(encodable),
Expand All @@ -19,6 +20,19 @@ extension TargetType {

return dictionary
}

/// 쿼리 파라미터 디버그를 위한 값 반환
var queryParameters: [String: Any]? {
switch task {
case .requestParameters(let parameters, let encoding):
if encoding is URLEncoding {
return parameters
}
return nil
default:
return nil
}
}
}

extension JSONEncoder {
Expand Down
66 changes: 66 additions & 0 deletions Project_Timer/Data/API/AuthV2API.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// AuthV2API.swift
// Project_Timer
//
// Created by Kang Minsang on 2024/09/29.
// Copyright © 2024 FDEE. All rights reserved.
//

import Foundation
import Moya

enum AuthV2API {
/// 존재하는 Username인지 확인해요.
case checkUsername(request: CheckUsernameRequest)
/// 인증 코드를 생성하여 대상에게 전송해요.
case postAuthcode(request: PostAuthCodeRequest)
/// 인증 코드를 검증해요.
case verifyAuthcode(request: VerifyAuthCodeRequest)
}

extension AuthV2API: TargetType {
var baseURL: URL {
return URL(string: NetworkURL.serverURL_V2 + "/api/auth")!
}

var path: String {
switch self {
case .checkUsername:
return "/accounts/check"
case .postAuthcode:
return "/code"
case .verifyAuthcode:
return "/code/verify"
}
}

var method: Moya.Method {
switch self {
case .checkUsername:
return .get
case .postAuthcode, .verifyAuthcode:
return .post
}
}

var task: Moya.Task {
switch self {
case .checkUsername(let request):
return .requestParameters(
parameters: Self.parameters(from: request),
encoding: URLEncoding.queryString
)
case .postAuthcode(let request):
return .requestJSONEncodable(request)
case .verifyAuthcode(let request):
return .requestJSONEncodable(request)
}
}

var headers: [String : String]? {
switch self {
case .checkUsername, .postAuthcode, .verifyAuthcode:
return nil
}
}
}
7 changes: 7 additions & 0 deletions Project_Timer/Data/NetworkURL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import Combine

final class NetworkURL {
static let shared = NetworkURL()
static var serverURL_V2: String {
#if DEBUG || DEVELOP
return "http://ec2-43-200-217-188.ap-northeast-2.compute.amazonaws.com:8080"
#else
return "http://ec2-43-200-217-188.ap-northeast-2.compute.amazonaws.com:8080"
#endif
}
private(set) var serverURL: String?
// Combine binding
private var cancellables = Set<AnyCancellable>()
Expand Down
41 changes: 41 additions & 0 deletions Project_Timer/Data/Repository/AuthV2Repository.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// AuthV2Repository.swift
// Project_Timer
//
// Created by Kang Minsang on 2024/09/29.
// Copyright © 2024 FDEE. All rights reserved.
//

import Foundation
import Moya
import Combine
import CombineMoya

final class AuthV2Repository {
private let api: TTProvider<AuthV2API>

init(api: TTProvider<AuthV2API>) {
self.api = api
}

func checkUsername(request: CheckUsernameRequest) -> AnyPublisher<CheckUsernameInfo, NetworkError> {
return self.api.request(.checkUsername(request: request))
.map(CheckUsernameResponse.self)
.map { $0.toDomain() }
.catchDecodeError()
}

func postAuthcode(request: PostAuthCodeRequest) -> AnyPublisher<PostAuthCodeInfo, NetworkError> {
return self.api.request(.postAuthcode(request: request))
.map(PostAuthCodeResponse.self)
.map { $0.toDomain() }
.catchDecodeError()
}

func verifyAuthCode(request: VerifyAuthCodeRequest) -> AnyPublisher<VerifyAuthCodeInfo, NetworkError> {
return self.api.request(.verifyAuthcode(request: request))
.map(VerifyAuthCodeResponse.self)
.map { $0.toDomain() }
.catchDecodeError()
}
}
15 changes: 15 additions & 0 deletions Project_Timer/Data/Request/PostAuthCodeRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// PostAuthCodeRequest.swift
// Project_Timer
//
// Created by Kang Minsang on 2024/09/29.
// Copyright © 2024 FDEE. All rights reserved.
//

import Foundation

struct PostAuthCodeRequest: Encodable {
let targetType: String
let targetValue: String
let authType: String
}
14 changes: 14 additions & 0 deletions Project_Timer/Data/Request/VerifyAuthCodeRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// VerifyAuthCodeRequest.swift
// Project_Timer
//
// Created by Kang Minsang on 2024/10/01.
// Copyright © 2024 FDEE. All rights reserved.
//

import Foundation

struct VerifyAuthCodeRequest: Encodable {
let authKey: String
let authCode: String
}
24 changes: 24 additions & 0 deletions Project_Timer/Data/Response/CheckUsernameResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// CheckUsernameResponse.swift
// Project_Timer
//
// Created by Kang Minsang on 2024/09/01.
// Copyright © 2024 FDEE. All rights reserved.
//

import Foundation

struct CheckUsernameResponse: Decodable {
let code: String
let message: String
let isPresent: Bool
}

extension CheckUsernameResponse {
func toDomain() -> CheckUsernameInfo {
return .init(
detailInfo: .init(code: self.code, message: self.message),
isNotExist: !self.isPresent
)
}
}
24 changes: 24 additions & 0 deletions Project_Timer/Data/Response/PostAuthCodeResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// PostAuthCodeResponse.swift
// Project_Timer
//
// Created by Kang Minsang on 2024/09/29.
// Copyright © 2024 FDEE. All rights reserved.
//

import Foundation

struct PostAuthCodeResponse: Decodable {
let code: String
let message: String
let authKey: String
}

extension PostAuthCodeResponse {
func toDomain() -> PostAuthCodeInfo {
return .init(
detailInfo: .init(code: self.code, message: self.message),
authKey: self.authKey
)
}
}
52 changes: 51 additions & 1 deletion Project_Timer/Data/Response/TTErrorResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,55 @@ import Foundation
struct TTErrorResponse: Decodable {
let code: String
let message: String
let errors: [String: String]
let errors: [TTError]

var logMessage: String {
return self.errors
.map { $0.logMessage }
.joined(separator: "\n")
}

var errorTitle: String {
switch self.code {
case "E9000":
return "잘못된 입력 오류"
case "E9001", "E9002", "E9003", "E9004", "E9005":
return "잘못된 요청 오류"
case "E9006":
return "인증정보 오류"
case "E9007":
return "잘못된 권한 오류"
case "E9999":
return "서버 오류"
default:
return "오류 발생"
}
}

var errorMessage: String {
switch code {
case "E9000":
return "입력값을 확인 후 다시 시도해주세요"
case "E9001", "E9002", "E9003", "E9004", "E9005":
return "개발자 실수로 오류가 발생했어요 🥲\n(\(self.code))"
case "E9006":
return "인증정보가 만료되어 다시 로그인해주세요"
case "E9007":
return "계속 문제가 발생하는 경우 문의해주세요\n(\(self.code))"
case "E9999":
return "서버문제가 발생했어요 🥲\n(\(self.code))"
default:
return "계속 문제가 발생하는 경우 문의해주세요\n(\(self.code))"
}
}
}

struct TTError: Decodable {
let field: String
let value: String
let reason: String

var logMessage: String {
return "[\(field) 값 오류](\(value)): \(reason)"
}
}
24 changes: 24 additions & 0 deletions Project_Timer/Data/Response/VerifyAuthCodeResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// VerifyAuthCodeResponse.swift
// Project_Timer
//
// Created by Kang Minsang on 2024/10/01.
// Copyright © 2024 FDEE. All rights reserved.
//

import Foundation

struct VerifyAuthCodeResponse: Decodable {
let code: String
let message: String
let authToken: String
}

extension VerifyAuthCodeResponse {
func toDomain() -> VerifyAuthCodeInfo {
return .init(
detailInfo: .init(code: self.code, message: self.message),
authToken: self.authToken
)
}
}
34 changes: 29 additions & 5 deletions Project_Timer/Data/TTProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,21 @@ final class TTProvider<T: TargetType>: MoyaProvider<T> {
super.request(token) { result in
switch result {
case .success(let response):
print("\nTTProvider success", token, "\(token.baseURL)\(token.path)")
// print("-->", String(data: response.data, encoding: .utf8), "\n")
let url = "[\(token.method.rawValue)] \(response.response?.url?.absoluteString ?? "No URL")"
let requestBody = response.request?.httpBody.flatMap { String(data: $0, encoding: .utf8) }
let responseBody = String(data: response.data, encoding: .utf8)

let debugInfo = """
✅ TTProvider success
================================================
1️⃣ moya: \(token)
2️⃣ URL: \(url)
3️⃣ Request Body: \(requestBody ?? "nil")
4️⃣ Response Body: \(responseBody ?? "nil")
================================================
"""
print(debugInfo)

if (200...299).contains(response.statusCode) {
promise(.success(response))
} else {
Expand All @@ -28,15 +41,26 @@ final class TTProvider<T: TargetType>: MoyaProvider<T> {
}
promise(.success(response))
case .failure(let error):
print("\nTTProvider failure", token, "\(token.baseURL)\(token.path)")
// print("-->", error.localizedDescription, "\n")
let url = "[\(token.method.rawValue)] \(token.baseURL)\(token.path), \(token.queryParameters ?? [:])"

let debugInfo = """
🚨 TTProvider failure
================================================
1️⃣ moya: \(token)
2️⃣ URL: \(url)
3️⃣ errorCode: \(error.errorCode)
4️⃣ errorDescription: \(error.localizedDescription)
================================================
"""
print(debugInfo)

promise(.failure(self.handleError(error)))
}
}
}
.eraseToAnyPublisher()
}

private func handleError(_ error: Error) -> NetworkError {
if let moyaError = error as? MoyaError {
switch moyaError {
Expand Down
14 changes: 14 additions & 0 deletions Project_Timer/Domain/Entity/CheckUsernameInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// CheckUsernameInfo.swift
// Project_Timer
//
// Created by Kang Minsang on 2024/09/01.
// Copyright © 2024 FDEE. All rights reserved.
//

import Foundation

struct CheckUsernameInfo {
let detailInfo: TTResponseDetailInfo
let isNotExist: Bool
}
14 changes: 14 additions & 0 deletions Project_Timer/Domain/Entity/PostAuthCodeInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// PostAuthCodeInfo.swift
// Project_Timer
//
// Created by Kang Minsang on 2024/09/29.
// Copyright © 2024 FDEE. All rights reserved.
//

import Foundation

struct PostAuthCodeInfo {
let detailInfo: TTResponseDetailInfo
let authKey: String
}
Loading