forked from AcaMate/AcaMate_iOS
[♻️] 엑세스 토큰으로 계정 정보 확인하는 로직 전체 변경
This commit is contained in:
parent
fea29d0cb8
commit
966dd4cb34
Binary file not shown.
|
@ -99,10 +99,11 @@ struct IntroView: View {
|
||||||
|
|
||||||
private func loadVersion() -> Future<VersionData, Error> {
|
private func loadVersion() -> Future<VersionData, Error> {
|
||||||
return Future { promise in
|
return Future { promise in
|
||||||
APIManager.shared.loadAPIData(url: "\(API_URL)",
|
let request = APIRequest(path: "/api/v1/in/app/version",
|
||||||
path: "/api/v1/in/app/version",
|
parameters: ["type":"I"],
|
||||||
parameters: ["type":"I"],
|
decoding: APIResponse<VersionData>.self)
|
||||||
decodingType: APIResponse<VersionData>.self)
|
|
||||||
|
APIManager.shared.loadAPIData(request)
|
||||||
.sink { completion in
|
.sink { completion in
|
||||||
switch completion {
|
switch completion {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
|
|
29
AcaMate/2. Model/API Request.swift
Normal file
29
AcaMate/2. Model/API Request.swift
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// API Request.swift
|
||||||
|
// AcaMate
|
||||||
|
//
|
||||||
|
// Created by TAnine on 3/18/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Alamofire
|
||||||
|
|
||||||
|
public struct APIRequest<T: APIResponseProtocol> {
|
||||||
|
let url, path: String
|
||||||
|
let method: HTTPMethod
|
||||||
|
var parameters: [String: Any]
|
||||||
|
let headers: HTTPHeaders
|
||||||
|
let decoding: T.Type
|
||||||
|
|
||||||
|
init(url: String = "\(API_URL)", path: String,
|
||||||
|
method: HTTPMethod = .get, headers: HTTPHeaders = [:],
|
||||||
|
parameters: [String : Any] = [:], decoding: T.Type) {
|
||||||
|
self.url = url
|
||||||
|
self.path = path
|
||||||
|
self.method = method
|
||||||
|
self.headers = headers
|
||||||
|
self.parameters = parameters
|
||||||
|
self.decoding = decoding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,13 +6,16 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
public protocol APIResponseProtocol: Decodable {
|
||||||
|
var status: Status { get }
|
||||||
|
}
|
||||||
|
|
||||||
class APIResponse<T: Codable>: Codable {
|
class APIResponse<T: Codable>: Codable, APIResponseProtocol {
|
||||||
let status: Status
|
let status: Status
|
||||||
let data: T?
|
let data: T?
|
||||||
}
|
}
|
||||||
|
|
||||||
class Status: Codable {
|
public class Status: Codable {
|
||||||
let code: APICode
|
let code: APICode
|
||||||
let message: String
|
let message: String
|
||||||
}
|
}
|
||||||
|
@ -58,6 +61,8 @@ enum APICode: Codable, RawRepresentable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// /api/v1/in/app/version ----------------
|
// /api/v1/in/app/version ----------------
|
||||||
|
|
||||||
class VersionData: Codable {
|
class VersionData: Codable {
|
||||||
|
@ -71,7 +76,15 @@ class Access: Codable {
|
||||||
let access: String
|
let access: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /api/v1/in/user ----------------
|
||||||
|
class User: Codable {
|
||||||
|
let uid, name, type: String
|
||||||
|
let device_id, push_token: String?
|
||||||
|
let auto_login_yn: Bool
|
||||||
|
let login_date: String
|
||||||
|
let birth: String?
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// /api/v1/in/user/login ----------------
|
// /api/v1/in/user/login ----------------
|
||||||
|
|
||||||
|
|
|
@ -18,56 +18,42 @@ class LoginViewModel: ObservableObject {
|
||||||
var bidArray: [String] = []
|
var bidArray: [String] = []
|
||||||
|
|
||||||
func USERPAITEST() {
|
func USERPAITEST() {
|
||||||
|
@UserDefault(key: "token", defaultValue: "accToken") var accToken
|
||||||
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh
|
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh
|
||||||
var acc = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJBTVRlc3RFbWFpbDIwMjUwMzE3IiwianRpIjoiYTQzN2Q4YjUtNzQyMi00NWVhLWFiNTktZWI2MTBkNDMwNWRlIiwiZXhwIjoxNzQyMjAwODQ3LCJpc3MiOiJBY2FNYXRlIiwiYXVkIjoiaHR0cHM6L2RldmFjYW1hdGUuaXBzdGVpbi5teWRzLm1lIn0.Y-xxdQWyu3BX_y5hlwWjAdxG5-QRZyHEgJ6T2pDkFRc"
|
let acc = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJBTVRlc3RFbWFpbDIwMjUwMzE4IiwianRpIjoiMjgwMjIwZDMtYzUwNS00YjFjLTgwMzgtZjBlNGJjYzM4MTE3IiwiZXhwIjoxNzQyMjYzMzgwLCJpc3MiOiJBY2FNYXRlIiwiYXVkIjoiaHR0cHM6L2RldmFjYW1hdGUuaXBzdGVpbi5teWRzLm1lIn0.f6kLKnsWhzlllSuYKxpFNuXuV4vOtJ2ox4IGSnxE67Y"
|
||||||
|
|
||||||
refresh = "tsLeVEtZTjy8iWDvT9vf7Kv7qQr3WgPjeNkFdMb9Rv4="
|
refresh = "MRo+1HIvaPgECXrvwmGvtUpxSk7Pip7KtGSoWDqmjVA="
|
||||||
|
|
||||||
APIManager.shared.loadAPIData(url: "\(API_URL)",
|
let request = APIRequest(path: "/api/v1/in/user",
|
||||||
path: "/api/v1/in/user/cancel",
|
parameters: ["token": accToken],
|
||||||
parameters: ["token": acc],
|
decoding: APIResponse<User>.self)
|
||||||
decodingType: APIResponse<String>.self)
|
|
||||||
.flatMap { response -> AnyPublisher<APIResponse<String>, Error> in
|
APIManager.shared.loadUserAPIData(request: request)
|
||||||
switch response.status.code {
|
.sink { completion in
|
||||||
case .inputErr(let code) where code == "101":
|
switch completion {
|
||||||
return APIManager.shared.reloadAccessToken()
|
case .failure(let error):
|
||||||
.flatMap { newAcc -> AnyPublisher<APIResponse<String>, Error> in
|
printLog("최종 에러: \(error)")
|
||||||
APIManager.shared.loadAPIData(url: "\(API_URL)",
|
case .finished:
|
||||||
path: "/api/v1/in/user/cancel",
|
break
|
||||||
parameters: ["token": (newAcc as! Access).access],
|
}
|
||||||
decodingType: APIResponse<String>.self)
|
} receiveValue: { response in
|
||||||
.eraseToAnyPublisher()
|
guard let user = response.data as? User else { return }
|
||||||
}
|
printLog("최종 값 : \(user.name), \(user.birth)")
|
||||||
.eraseToAnyPublisher()
|
|
||||||
default:
|
|
||||||
return Just(response)
|
|
||||||
.setFailureType(to: Error.self)
|
|
||||||
.eraseToAnyPublisher()
|
|
||||||
}
|
}
|
||||||
}
|
.store(in: &cancellables)
|
||||||
.sink { completion in
|
|
||||||
switch completion {
|
|
||||||
case .failure(let error):
|
|
||||||
printLog("최종 \(error)")
|
|
||||||
case .finished:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} receiveValue: { response in
|
|
||||||
printLog("최종: \(response)")
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func loginAction(type: SNSLoginType) {
|
func loginAction(type: SNSLoginType) {
|
||||||
|
|
||||||
LoginController().login(type)
|
LoginController().login(type)
|
||||||
.flatMap{ snsId in
|
.flatMap{ snsId in
|
||||||
APIManager.shared.loadAPIData(url: "\(API_URL)",
|
APIManager.shared.loadAPIData(APIRequest(path: "/api/v1/in/user/login",
|
||||||
path: "/api/v1/in/user/login",
|
parameters: [
|
||||||
parameters: [
|
"acctype": "\(type == .Apple ? "ST00": "ST01")",
|
||||||
"acctype": "\(type == .Apple ? "ST00": "ST01")",
|
"sns_id": "\(snsId.snsId)"
|
||||||
"sns_id": "\(snsId.snsId)"
|
],
|
||||||
],
|
decoding: APIResponse<User_Token>.self))
|
||||||
decodingType: APIResponse<User_Token>.self)
|
|
||||||
.map { response in
|
.map { response in
|
||||||
return (snsId: snsId.snsId, response: response)
|
return (snsId: snsId.snsId, response: response)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,12 @@ class SelectAcademyViewModel: ObservableObject {
|
||||||
func loadAcademy() {
|
func loadAcademy() {
|
||||||
@UserDefault(key: "token", defaultValue: "accToken") var token
|
@UserDefault(key: "token", defaultValue: "accToken") var token
|
||||||
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh
|
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh
|
||||||
APIManager.shared.loadAPIData(url: "\(API_URL)",
|
|
||||||
path: "/api/v1/in/user/academy",
|
let request = APIRequest(path: "/api/v1/in/user/academy",
|
||||||
method: .get,
|
parameters: ["token": token, "refresh": refresh],
|
||||||
parameters: ["token": token, "refresh": refresh],
|
decoding: APIResponse<[AcademyName]>.self)
|
||||||
decodingType: APIResponse<[AcademyName]>.self)
|
|
||||||
|
APIManager.shared.loadAPIData(request)
|
||||||
.sink { completion in
|
.sink { completion in
|
||||||
switch completion {
|
switch completion {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
|
|
|
@ -14,29 +14,26 @@ public class APIManager {
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
public static let shared = APIManager()
|
public static let shared = APIManager()
|
||||||
|
|
||||||
|
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh
|
||||||
|
@UserDefault(key: "token", defaultValue: "accToken") var accToken
|
||||||
|
|
||||||
private init(cancellables: Set<AnyCancellable> = Set<AnyCancellable>()) {
|
private init(cancellables: Set<AnyCancellable> = Set<AnyCancellable>()) {
|
||||||
self.cancellables = cancellables
|
self.cancellables = cancellables
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadAPIData<T: Decodable>(url: String, path: String,
|
public func loadAPIData<T: APIResponseProtocol>(_ request: APIRequest<T>) -> Future<T, Error> {
|
||||||
method: HTTPMethod = .get,
|
let encoding: ParameterEncoding = (request.method == .get) ? URLEncoding.default : JSONEncoding.default
|
||||||
parameters: [String: Any],
|
|
||||||
headers: HTTPHeaders = [:],//["Accept": "application/json"],
|
|
||||||
decodingType: T.Type) -> Future<T, Error> {
|
|
||||||
let encoding: ParameterEncoding = (method == .get) ? URLEncoding.default : JSONEncoding.default
|
|
||||||
return Future { promise in
|
return Future { promise in
|
||||||
printLog(parameters)
|
printLog(request.parameters)
|
||||||
AF.request("\(url)\(path)",
|
AF.request("\(request.url)\(request.path)",
|
||||||
method: method,
|
method: request.method,
|
||||||
parameters: parameters,
|
parameters: request.parameters,
|
||||||
encoding: encoding,
|
encoding: encoding,
|
||||||
headers: headers
|
headers: request.headers
|
||||||
)
|
)
|
||||||
.validate(statusCode: 200 ..< 300)
|
.validate(statusCode: 200 ..< 300)
|
||||||
// .responseString { response in
|
.responseDecodable(of: request.decoding) { response in
|
||||||
// printLog(response)
|
|
||||||
// }
|
|
||||||
.responseDecodable(of: decodingType) { response in
|
|
||||||
|
|
||||||
switch response.result {
|
switch response.result {
|
||||||
case .success(let value):
|
case .success(let value):
|
||||||
|
@ -53,48 +50,83 @@ public class APIManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public func reloadAccessToken() -> Future<Any, Error> {
|
public func reloadAccessToken() -> Future<Any, Error> {
|
||||||
|
|
||||||
@UserDefault(key: "refresh", defaultValue: "refreshToken") var refresh
|
|
||||||
return Future { [weak self] promise in
|
return Future { [weak self] promise in
|
||||||
guard let self = self else {return}
|
guard let self = self else {return}
|
||||||
APIManager.shared.loadAPIData(url: "\(API_URL)",
|
|
||||||
path: "/api/v1/in/app/retryAccess",
|
let request = APIRequest.init(path: "/api/v1/in/app/retryAccess",
|
||||||
parameters: ["refresh": refresh],
|
parameters: ["refresh": refresh],
|
||||||
decodingType: APIResponse<Access>.self)
|
decoding: APIResponse<Access>.self)
|
||||||
.sink { completion in
|
|
||||||
switch completion {
|
APIManager.shared.loadAPIData(request)
|
||||||
case .failure(let error):
|
.sink { completion in
|
||||||
promise(.failure(error))
|
switch completion {
|
||||||
printLog("\(error)")
|
case .failure(let error):
|
||||||
case .finished:
|
promise(.failure(error))
|
||||||
printLog("엑세스 토큰 재발급 완료")
|
printLog("\(error)")
|
||||||
break
|
case .finished:
|
||||||
}
|
printLog("엑세스 토큰 재발급 완료")
|
||||||
} receiveValue: { response in
|
break
|
||||||
guard let accToken = response as? APIResponse<Access> else {
|
}
|
||||||
promise(.failure(ACA_ERROR("Unknown ERROR")))
|
} receiveValue: { response in
|
||||||
return
|
guard let accToken = response as? APIResponse<Access> else {
|
||||||
}
|
promise(.failure(ACA_ERROR("Unknown ERROR")))
|
||||||
|
return
|
||||||
switch accToken.status.code {
|
}
|
||||||
case .success(let code):
|
|
||||||
if code == "000" {
|
switch accToken.status.code {
|
||||||
if let tknData = accToken.data { promise(.success(tknData)) }
|
case .success(let code):
|
||||||
|
if code == "000" {
|
||||||
|
if let tknData = accToken.data { promise(.success(tknData)) }
|
||||||
|
}
|
||||||
|
case .inputErr(let code):
|
||||||
|
// 로그인 화면으로 전환하기
|
||||||
|
promise(.failure(ACA_ERROR("Refresh token ERROR(\(code), \(accToken.status.message)")))
|
||||||
|
default:
|
||||||
|
// 그외에 서버에서 처리를 하다가 문제가 생겨서 발생하는 에러는 여기로 보낼거임
|
||||||
|
promise(.failure(ACA_ERROR("Unknown ERROR")))
|
||||||
}
|
}
|
||||||
case .inputErr(let code):
|
|
||||||
// 로그인 화면으로 전환하기
|
|
||||||
promise(.failure(ACA_ERROR("Refresh token ERROR(\(code), \(accToken.status.message)")))
|
|
||||||
default:
|
|
||||||
// 그외에 서버에서 처리를 하다가 문제가 생겨서 발생하는 에러는 여기로 보낼거임
|
|
||||||
promise(.failure(ACA_ERROR("Unknown ERROR")))
|
|
||||||
}
|
}
|
||||||
}
|
.store(in: &self.cancellables)
|
||||||
.store(in: &self.cancellables)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public func loadUserAPIData<T: APIResponseProtocol & Codable>(request: APIRequest<T>) -> Future<T, Error>{
|
||||||
|
return Future { [weak self] promise in
|
||||||
|
guard let self = self else {return}
|
||||||
|
printLog(request.parameters["token"])
|
||||||
|
loadAPIData(request)
|
||||||
|
.flatMap { (response: T) -> AnyPublisher<T, Error> in
|
||||||
|
switch response.status.code {
|
||||||
|
case .inputErr(let code) where code == "101":
|
||||||
|
return self.reloadAccessToken()
|
||||||
|
.flatMap { response -> AnyPublisher<T, Error> in
|
||||||
|
self.accToken = (response as! Access).access
|
||||||
|
var updateRequest = request
|
||||||
|
updateRequest.parameters["token"] = self.accToken
|
||||||
|
return APIManager.shared.loadAPIData(updateRequest)
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
default:
|
||||||
|
return Just(response)
|
||||||
|
.setFailureType(to: Error.self)
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sink { completion in
|
||||||
|
switch completion {
|
||||||
|
case .failure(let error):
|
||||||
|
promise(.failure(error))
|
||||||
|
case .finished:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} receiveValue: { finalResponse in
|
||||||
|
promise(.success(finalResponse))
|
||||||
|
}
|
||||||
|
.store(in: &self.cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user