Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save hertz315/3d53d561ea8d8d0c9d4eb27cb9444b5a to your computer and use it in GitHub Desktop.
Save hertz315/3d53d561ea8d8d0c9d4eb27cb9444b5a to your computer and use it in GitHub Desktop.
API호출 + API 동시호출 + API 연쇄호출 Combine 방식

GET, POST, PUT, DELETE, 연쇄호출, 동시호출 Combine 방식

//
//  BeautistUserApi+Combine.swift
//  Bueatist
//
//  Created by Hertz on 12/11/22.
//

import Foundation
import Combine
import CombineExt

extension BeautistUserApi {
    
    // ⭐️ 성공
    /// - Parameters:
    ///   - userName: 유저닉네임
    ///   - email: 유저이메일
    ///   - password: 유저패스워드
    // MARK: - 회원가입 Api - "POST"
    static func signupWithPublisher(userName: String, email: String, password: String) -> AnyPublisher<UserResponse, ApiError> {
        
        /// 파람
        let requestParams: [String:Any] = [
            "username":userName,
            "email":email,
            "password":password
        ]
        
        // MARK: - URLRequest를 만든다
        let urlString: String = baseURL + "users"
        
        guard let url: URL = URL(string: urlString) else {
            return Fail(error: ApiError.notAllowUrl).eraseToAnyPublisher()
        }
        
        var urlRequest: URLRequest = URLRequest(url: url)
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
        urlRequest.addValue("WCONfRfv8aio2yPtqOYWcWZKMltIj9IkkkCkFeyl", forHTTPHeaderField: "X-Parse-Application-Id")
        urlRequest.addValue("9EjhBUWG4G9aql4Q2GlTr9NqriQxbpaR2XCYQTSg", forHTTPHeaderField: "X-Parse-REST-API-Key")
        urlRequest.addValue("1", forHTTPHeaderField: "X-Parse-Revocable-Session")
        urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
        urlRequest.httpMethod = "POST"
        
        do {
            // 딕셔너리를 JSONData 로 만들기
            let jsonData: Data = try JSONSerialization.data(withJSONObject: requestParams, options: [.prettyPrinted])
            // JSON형태로 만든 데이터를 httpBody에 넣기
            urlRequest.httpBody = jsonData
        } catch {
            // JSON serialization failed
            return Fail(error: ApiError.jsonEncodingError).eraseToAnyPublisher()
        }
        
        // MARK: - ⭐️ URLSession.DataTaskPublisher -> AnyPublisher<UserResponse, ApiError> 형태로 변경해서 리턴
        return URLSession.shared.dataTaskPublisher(for: urlRequest)
            .tryMap({ (data: Data, response: URLResponse) -> Data in
                
                guard let httpResponse = response as? HTTPURLResponse else {
                    print("❗️Bad Status Code❗️")
                    throw ApiError.unKnown(nil)
                }
                
                switch httpResponse.statusCode {
                case 401:
                    throw ApiError.unAuthorized
                default:
                    print("default: \(httpResponse.statusCode)⭐️")
                }
                
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
                return data
                
            })
            .decode(type: UserResponse.self, decoder: JSONDecoder())
            .mapError({ dataTaskPublisherErrorType -> ApiError in
                
                if let error = dataTaskPublisherErrorType as? ApiError {
                    return error
                }
                
                if dataTaskPublisherErrorType is DecodingError {
                    return ApiError.decodingError
                }
                
                return ApiError.unKnown(nil)
                
            })
            .eraseToAnyPublisher()
    }
    
    // ⭐️
    /// - Parameters:
    ///   - userName: 유저이름
    ///   - password: 유저패스워드
    // MARK: - 로그인하기 API - "GET"
    static func loginWithPublisher(userName: String, password: String) -> AnyPublisher<UserResponse, ApiError> {
        
        // MARK: - URLRequest를 만든다
        // https://parseapi.back4app.com/login?username=hertz315&password=%40%40Ghdrn315
        var urlComponents = URLComponents(string: baseURL + "login?")!
        urlComponents.queryItems = [
            URLQueryItem(name: "username", value: userName),
            URLQueryItem(name: "password", value: password)
        ]
        
        guard let url = urlComponents.url else {
            // 에러를 보내고 데이터 스트림 끊어 버리기
            return Fail(error: ApiError.notAllowUrl) // ⭐️ Fail 타입 을 AnyPulisher타입으로 변경해줘야 함
                .eraseToAnyPublisher()
        }
        
        
        // URLRequest 생성
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "GET"
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
        urlRequest.addValue("WCONfRfv8aio2yPtqOYWcWZKMltIj9IkkkCkFeyl", forHTTPHeaderField: "X-Parse-Application-Id")
        urlRequest.addValue("9EjhBUWG4G9aql4Q2GlTr9NqriQxbpaR2XCYQTSg", forHTTPHeaderField: "X-Parse-REST-API-Key")
        urlRequest.addValue("1", forHTTPHeaderField: "X-Parse-Revocable-Session")
        
        // MARK: - dataTaskPublisher
        return URLSession.shared.dataTaskPublisher(for: urlRequest)
        // ⭐️ 에러를 던저야 되기 때문에 .map 말고 .tryMap 사용해야 함
            .tryMap({ (data: Data, response: URLResponse) -> Data in
                
                guard let httpResponse = response as? HTTPURLResponse else {
                    print("❗️Bad Status Code❗️")
                    throw ApiError.unKnown(nil)
                }
                
                switch httpResponse.statusCode {
                case 401:
                    // 에러를 던지면 밖으로 나가기 때문에 리턴안해도 됨
                    throw ApiError.unAuthorized
                default:
                    print("default: \(httpResponse.statusCode)⭐️")
                }
                
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
                return data
            }) // Data
            .decode(type: UserResponse.self, decoder: JSONDecoder())
            .tryMap({ response in
                guard let content = response.objectID, !content.isEmpty else {
                    throw ApiError.userNotCreated
                }
                return response
            })
            .mapError({ error -> ApiError in
                // dataTaskPublisher 형태의 에러를 커스텀 Error 타입으로 변경📌
                if let err = error as? ApiError {
                    return err
                }
                
                // 디코딩할때 발생핤수 있는 에러를 커스텀 Error 타입으로 변경📌
                if error is DecodingError {
                    return ApiError.decodingError
                }
                
                return ApiError.unKnown(nil)
            })
            .eraseToAnyPublisher()
        
    }
    
    
    // ⭐️
    /// - Parameters:
    ///   - objectId: 유저객체ID
    ///   - completion: 응답타입 클로저 터트리기
    // MARK: - 특정 유저 검색하기 API "GET"
    static func userRetrievingWithPublisher(objectId: String) -> AnyPublisher<UserResponse, ApiError> {
        
        // MARK: - URLRequest를 만든다
        // https://parseapi.back4app.com/users/ndDZyHxTVc
        // baseURL = https://parseapi.back4app.com/
        let urlString = baseURL + "users/" + objectId
        
        guard let url = URL(string: urlString) else {
            return Fail(error: ApiError.notAllowUrl).eraseToAnyPublisher()
        }
        
        // URLRequest 생성
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "GET"
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
        urlRequest.addValue("WCONfRfv8aio2yPtqOYWcWZKMltIj9IkkkCkFeyl", forHTTPHeaderField: "X-Parse-Application-Id")
        urlRequest.addValue("9EjhBUWG4G9aql4Q2GlTr9NqriQxbpaR2XCYQTSg", forHTTPHeaderField: "X-Parse-REST-API-Key")
        
        // MARK: - URLSession으로 API를 호출하기
        return URLSession.shared.dataTaskPublisher(for: urlRequest)
            .tryMap{ (data: Data, response: URLResponse) -> Data in
                
                // 응답값이 HTTPURLResponse 응답값이 없다면 에러던지기
                guard let httpResponse = response as? HTTPURLResponse else {
                    print("❗️Bad Status Code❗️")
                    throw ApiError.unKnown(nil)
                }
                
                // httpResponse 상태코드가 401 회원 인증 에러❗️
                switch httpResponse.statusCode {
                case 401:
                    throw ApiError.unAuthorized
                default:
                    print("default: \(httpResponse.statusCode)⭐️")
                }
                
                // 만약 상태 응답값 코드가 200~299 사이가 아니라면 에러던지기❗️
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
                return data // Data
            }
        // Data -> 디코딩
            .decode(type: UserResponse.self, decoder: JSONDecoder())
        // 디코딩 상태보고 파싱한 에러의 상태에 따라 에러처리
        // mapError로 에러 타입을 변경한다 ⭐️any Error -> BeautistUserApi.ApiError⭐️
            .mapError({ error -> ApiError in
                // dataTaskPublisher 형태의 에러를 커스텀 Error 타입으로 변경📌
                if let err = error as? ApiError {
                    return err
                }
                
                // 디코딩할때 발생핤수 있는 에러를 커스텀 Error 타입으로 변경📌
                if error is DecodingError {
                    return ApiError.decodingError
                }
                
                return ApiError.unKnown(nil)
            })
            .eraseToAnyPublisher()
        
    }
    
    // ⭐️
    /// - Parameters:
    ///   - sessionToken: 세션토큰
    ///   - completion: 응답타입 클로저 터트리기
    // MARK: - 현재 사용자 검색하기 Api "GET"
    static func currentUserRetrievingWithPublisher(sessionToken: String) -> AnyPublisher<UserResponse, ApiError> {
        
        // MARK: - URLRequest를 만든다
        // https://parseapi.back4app.com/users/me
        // baseURL = https://parseapi.back4app.com/
        let urlString = baseURL + "users/" + "me"
        
        guard let url = URL(string: urlString) else {
            return Fail(error: ApiError.notAllowUrl).eraseToAnyPublisher()
        }
        
        // URLRequest 생성
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "GET"
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
        urlRequest.addValue("WCONfRfv8aio2yPtqOYWcWZKMltIj9IkkkCkFeyl", forHTTPHeaderField: "X-Parse-Application-Id")
        urlRequest.addValue("9EjhBUWG4G9aql4Q2GlTr9NqriQxbpaR2XCYQTSg", forHTTPHeaderField: "X-Parse-REST-API-Key")
        urlRequest.addValue(sessionToken, forHTTPHeaderField: "X-Parse-Session-Token")
        
        // MARK: - URLSession으로 API를 호출하기
        return URLSession.shared.dataTaskPublisher(for: urlRequest)
            .tryMap({ (data: Data, response: URLResponse) -> Data in
                guard let httpResponse = response as? HTTPURLResponse else {
                    print("❗️Bad Status Code❗️")
                    throw ApiError.unKnown(nil)
                }
                
                switch httpResponse.statusCode {
                case 401:
                    // 에러를 던지면 밖으로 나가기 때문에 리턴안해도 됨
                    throw ApiError.unAuthorized
                default:
                    print("default: \(httpResponse.statusCode)⭐️")
                }
                
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
                return data
                
            })
            .decode(type: UserResponse.self, decoder: JSONDecoder())
            .mapError { dataTaskErrorType -> ApiError in
                
                if let error = dataTaskErrorType as? ApiError {
                    return error
                }
                
                if dataTaskErrorType is DecodingError {
                    return ApiError.decodingError
                }
                
                return ApiError.unKnown(nil)
            }
            .eraseToAnyPublisher()
        
    }
    
    
    /// - Parameters:
    ///   - sessionToken: 세션토큰
    ///   - userName: 수정할 유저닉네임
    ///   - email: 수정할 이메일
    // MARK: - 유저 정보 수정 Api "PUT
    static func editUserInformationWithPublisher(sessionToken: String, objectId: String, userName: String, email: String) -> AnyPublisher<UserResponse, ApiError> {
        
        // MARK: - URLRequest를 만든다
        // https://parseapi.back4app.com/users/jSSAQpjmWC
        // baseURL = https://parseapi.back4app.com/
        let urlString = baseURL + "users/" + objectId
        
        let requestParams: [String:Any] = [
            "username":userName,
            "email":email,
        ]
        
        guard let url: URL = URL(string: urlString) else {
            return Fail(error: ApiError.notAllowUrl).eraseToAnyPublisher()
        }
        
        var urlRequest: URLRequest = URLRequest(url: url)
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
        urlRequest.addValue("WCONfRfv8aio2yPtqOYWcWZKMltIj9IkkkCkFeyl", forHTTPHeaderField: "X-Parse-Application-Id")
        urlRequest.addValue("9EjhBUWG4G9aql4Q2GlTr9NqriQxbpaR2XCYQTSg", forHTTPHeaderField: "X-Parse-REST-API-Key")
        urlRequest.addValue(sessionToken, forHTTPHeaderField: "X-Parse-Session-Token")
        urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
        urlRequest.httpMethod = "PUT"
        
        do {
            // 딕셔너리를 JSONData 로 만들기
            let jsonData: Data = try JSONSerialization.data(withJSONObject: requestParams, options: [.prettyPrinted])
            // JSON형태로 만든 데이터를 httpBody에 넣기
            urlRequest.httpBody = jsonData
        } catch {
            // JSON serialization failed
            return Fail(error: ApiError.jsonEncodingError).eraseToAnyPublisher()
        }
        
        return URLSession.shared.dataTaskPublisher(for: urlRequest)
            .tryMap { (data: Data, response: URLResponse) -> Data in
                guard let httpResponse = response as? HTTPURLResponse else {
                    print("❗️Bad Status Code❗️")
                    throw ApiError.unKnown(nil)
                }
                
                switch httpResponse.statusCode {
                case 401:
                    // 에러를 던지면 밖으로 나가기 때문에 리턴안해도 됨
                    throw ApiError.unAuthorized
                default:
                    print("default: \(httpResponse.statusCode)⭐️")
                }
                
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
                return data
                
            }
            .decode(type: UserResponse.self, decoder: JSONDecoder())
            .mapError { dataTaskPublisherError -> ApiError in
                
                if let error = dataTaskPublisherError as? ApiError {
                    return error
                }
                
                if dataTaskPublisherError is DecodingError {
                    return ApiError.decodingError
                }
                
                return ApiError.unKnown(nil)
            }
            .eraseToAnyPublisher()
        
    }
    
    // ⭐️
    /// - Parameters:
    ///   - sessionToken: 유저 세션토큰
    ///   - objectId: 유저 아이디
    // MARK: - 유저 삭제하기 Api "DELETE"
    static func deleteUserWithPublisher(sessionToken: String, objectId: String) -> AnyPublisher<UserResponse, ApiError> {
        
        print(#fileID, #function, #line, "deleteUserAPI 호출됨⭐️")
        
        // MARK: - URLRequest를 만든다
        // https://parseapi.back4app.com/users/a9JbehvWhv
        // baseURL = https://parseapi.back4app.com/
        let urlString = baseURL + "users/" + objectId
        
        guard let url: URL = URL(string: urlString) else {
            return Fail(error: ApiError.notAllowUrl).eraseToAnyPublisher()
        }
        
        var urlRequest: URLRequest = URLRequest(url: url)
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
        urlRequest.addValue("WCONfRfv8aio2yPtqOYWcWZKMltIj9IkkkCkFeyl", forHTTPHeaderField: "X-Parse-Application-Id")
        urlRequest.addValue("9EjhBUWG4G9aql4Q2GlTr9NqriQxbpaR2XCYQTSg", forHTTPHeaderField: "X-Parse-REST-API-Key")
        urlRequest.addValue(sessionToken, forHTTPHeaderField: "X-Parse-Session-Token")
        urlRequest.httpMethod = "DELETE"
        
        // MARK: - URLSession으로 API를 호출한다 && API호출에 대한 응답을 받는다
        // 만든URLRequest를 가지고 데이터 추출
        return URLSession.shared.dataTaskPublisher(for: urlRequest)
            .tryMap({ (data: Data, response: URLResponse) -> Data in
                guard let httpResponse = response as? HTTPURLResponse else {
                    print("❗️Bad Status Code❗️")
                    throw ApiError.unKnown(nil)
                }
                
                switch httpResponse.statusCode {
                case 401:
                    // 에러를 던지면 밖으로 나가기 때문에 리턴안해도 됨
                    throw ApiError.unAuthorized
                default:
                    print("default: \(httpResponse.statusCode)⭐️")
                }
                
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
                return data
                
            })
            .decode(type: UserResponse.self, decoder: JSONDecoder())
            .mapError { dataTaskPublisherErrorType -> ApiError in
                if let error = dataTaskPublisherErrorType as? ApiError {
                    return error
                }
                
                if dataTaskPublisherErrorType is DecodingError  {
                    return ApiError.decodingError
                }
                
                return ApiError.unKnown(nil)
                
            }
            .eraseToAnyPublisher()
        
    }
    
    /// - Parameters:
    ///   - email: 유저이메일
    // MARK: - 확인이메일요청 Api "POST"
    static func verificationEmailRequestWithPublisher(email: String) -> AnyPublisher<UserResponse, ApiError> {
        
        let requestParams: [String:Any] = [
            "email":email,
        ]
        
        // MARK: - URLRequest를 만든다
        // https://parseapi.back4app.com/verificationEmailRequest
        // baseURL = https://parseapi.back4app.com/
        let urlString = baseURL + "verificationEmailRequest/"
        
        guard let url: URL = URL(string: urlString) else {
            return Fail(error: ApiError.notAllowUrl).eraseToAnyPublisher()
        }
        
        var urlRequest: URLRequest = URLRequest(url: url)
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
        urlRequest.addValue("WCONfRfv8aio2yPtqOYWcWZKMltIj9IkkkCkFeyl", forHTTPHeaderField: "X-Parse-Application-Id")
        urlRequest.addValue("9EjhBUWG4G9aql4Q2GlTr9NqriQxbpaR2XCYQTSg", forHTTPHeaderField: "X-Parse-REST-API-Key")
        urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
        urlRequest.httpMethod = "POST"
        
        
        do {
            // 딕셔너리를 JSONData 로 만들기
            let jsonData: Data = try JSONSerialization.data(withJSONObject: requestParams, options: [.prettyPrinted])
            // JSON형태로 만든 데이터를 httpBody에 넣기
            urlRequest.httpBody = jsonData
        } catch {
            // JSON serialization failed
            return Fail(error: ApiError.jsonEncodingError).eraseToAnyPublisher()
        }
        
        return URLSession.shared.dataTaskPublisher(for: urlRequest)
        // tryMap: 클로저 내부에서 예외가 던져질 수 있는 연산이 있을때 사용
            .tryMap({ (data: Data, response: URLResponse) -> Data in
                guard let httpResponse = response as? HTTPURLResponse else {
                    print("❗️Bad Status Code❗️")
                    throw ApiError.unKnown(nil)
                }
                
                switch httpResponse.statusCode {
                case 401:
                    // 에러를 던지면 밖으로 나가기 때문에 리턴안해도 됨
                    throw ApiError.unAuthorized
                default:
                    print("default: \(httpResponse.statusCode)⭐️")
                }
                
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
                return data
            })
            .decode(type: UserResponse.self, decoder: JSONDecoder())
            .mapError { dataTaskPublisherErrorType -> ApiError in
                
                if let error = dataTaskPublisherErrorType as? ApiError {
                    return error
                }
                
                if dataTaskPublisherErrorType is DecodingError {
                    return ApiError.decodingError
                }
                
                return ApiError.unKnown(nil)
                
            }
            .eraseToAnyPublisher()
        
    }
    
    /// - Parameters:
    ///   - email: 유저이메일
    // MARK: - 확인이메일요청 Api "POST"
    static func requestPasswordResetWithPublisher(email: String) -> AnyPublisher<UserResponse, ApiError> {
        
        let requestParams: [String:Any] = [
            "email":email,
        ]
        
        // MARK: - URLRequest를 만든다
        // https://parseapi.back4app.com/requestPasswordReset
        // baseURL = https://parseapi.back4app.com/
        let urlString = baseURL + "requestPasswordReset"
        
        guard let url: URL = URL(string: urlString) else {
            return Fail(error: ApiError.notAllowUrl).eraseToAnyPublisher()
        }
        
        var urlRequest: URLRequest = URLRequest(url: url)
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
        urlRequest.addValue("WCONfRfv8aio2yPtqOYWcWZKMltIj9IkkkCkFeyl", forHTTPHeaderField: "X-Parse-Application-Id")
        urlRequest.addValue("9EjhBUWG4G9aql4Q2GlTr9NqriQxbpaR2XCYQTSg", forHTTPHeaderField: "X-Parse-REST-API-Key")
        urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
        urlRequest.httpMethod = "POST"
        
        
        do {
            // 딕셔너리를 JSONData 로 만들기
            let jsonData: Data = try JSONSerialization.data(withJSONObject: requestParams, options: [.prettyPrinted])
            // JSON형태로 만든 데이터를 httpBody에 넣기
            urlRequest.httpBody = jsonData
        } catch {
            // JSON serialization failed
            return Fail(error: ApiError.jsonEncodingError).eraseToAnyPublisher()
        }
        
        
        return URLSession.shared.dataTaskPublisher(for: urlRequest)
            .tryMap { (data: Data, response: URLResponse) -> Data in
                guard let httpResponse = response as? HTTPURLResponse else {
                    print("❗️Bad Status Code❗️")
                    throw ApiError.unKnown(nil)
                }
                
                switch httpResponse.statusCode {
                case 401:
                    // 에러를 던지면 밖으로 나가기 때문에 리턴안해도 됨
                    throw ApiError.unAuthorized
                default:
                    print("default: \(httpResponse.statusCode)⭐️")
                }
                
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
                return data
                
            }
            .decode(type: UserResponse.self, decoder: JSONDecoder())
            .mapError { dataTaskPublisherErrorType -> ApiError in
                
                if let error = dataTaskPublisherErrorType as? ApiError {
                    return error
                }
                
                if dataTaskPublisherErrorType is DecodingError {
                    return ApiError.decodingError
                }
                
                return ApiError.unKnown(nil)
                
            }
            .eraseToAnyPublisher()
    }
    
    // ⭐️
    /// - Parameters:
    ///   - userName: 유저닉네임
    ///   - email: 유저이메일
    ///   - password: 유저페스워드
    // MARK: - 회원가입하고 로그인하기 / 연쇄 API 호출⭐️
    static func signupUserAndLoginUserWithPublisher(userName: String, email: String, password: String) -> AnyPublisher<UserResponse, ApiError> {
        // 회원가입이 성공하면 리턴 그후 FlatMap오퍼레이터 사용하여 로그인 API 호출
        return self.signupWithPublisher(userName: userName, email: email, password: password)
            .map { _ in
                self.loginWithPublisher(userName: userName, password: password)
            }
            .switchToLatest()
            .eraseToAnyPublisher()

    }
    
    // ⭐️
    //sessionToken: String, objectId: String
    /// - Parameters:
    ///   - sessionTokens: 삭제할 유저 토큰 배열
    ///   - ObjectIds: 삭제할 유저 Id 배열
    // MARK: - 동시 유저 삭제 / 동시 API 호출⭐️
    static func deleteSelectedUsersWithPublisher(deleteUserTokenAndIdDictionary: [String:String]) -> AnyPublisher<[String:String], ApiError> {
        
        let apiCallPublishers: [AnyPublisher<[String : String], BeautistUserApi.ApiError>] =
        
            deleteUserTokenAndIdDictionary.map { id -> AnyPublisher<[String:String], ApiError> in
            
            return self.deleteUserWithPublisher(sessionToken: id.key, objectId: id.value)
                .map { [$0.sessionToken ?? "" : $0.objectID ?? ""] }
                .eraseToAnyPublisher()
        }
        
        return Publishers.MergeMany(apiCallPublishers).eraseToAnyPublisher()
        
    }
    
    
}

뷰모델

        
        // MARK: - 회원가입
        BeautistUserApi.signupWithPublisher(userName: "hon315", email: "hon315@gmail.com", password: "hon315")
        // sink 로 이벤트 받기(구독) ⭐️
            .sink { [weak self] completion in
                guard let self = self else {return}
                
                switch completion {
                case .finished:
                    print("VM : signupWithPublisher : 회원가입 : (완료)스트림끊킴❗️")
                case .failure(let failure):
                    self.handleError(failure)
                }
            } receiveValue: { response in
                print("VM / signupWithPublisher / \(response)")
            }
            .store(in: &subscriptions)
        
        
        
        // MARK: - 로그인
        BeautistUserApi.loginWithPublisher(userName: "hon315", password: "hon315")
            .sink { [weak self] completion in // 클로저이기 때문에 강한참조예방
                
                guard let self = self else { return }
                switch completion {
                case .finished: // 완료되었을
                    print("VM : loginWithPublisher : 로그인 :(완료)스트림끊킴❗️")
                case .failure(let failure): // 실패되었을때
                    self.handleError(failure)
                }
                
                
            } receiveValue: { response in
                print("VM / loginWithPublisher / \(response)")
            }
            .store(in: &subscriptions)
        
        // MARK: - 연쇄호출
        // MARK: - 회원가입하고 로그인하기
        BeautistUserApi.signupUserAndLoginUserWithPublisher(userName: "m",
                                                            email: "m@gmail.com",
                                                            password: "m")
        .sink { [weak self] completion in // 클로저이기 때문에 강한참조예방
            guard let self = self else { return }
            switch completion {
            case .finished: // 완료되었을
                print("VM : signupUserAndLoginUserWithPublisher : 회원가입 후 로그인 :(완료)스트림끊킴❗️")
            case .failure(let failure): // 실패되었을때
                self.handleError(failure)
            }
            
        } receiveValue: { response in
            print("VM / signupUserAndLoginUserWithPublisher / \(response)")
        }
        .store(in: &subscriptions)
        
        // MARK: - 동시호출
        BeautistUserApi.deleteSelectedUsersWithPublisher(deleteUserTokenAndIdDictionary: [
            "r:53a90e1004490c8cf28902ed25a298ab" : "rV7sQsgLEj",
            "r:ba7548720b6664c2ef430028e117ae0c" : "ZE3eAP1hC8",
            "r:0a2a66b54a78b2f56844326f0cc1e2cc" : "Dh5MlegJhR"
        ])
        .sink { [weak self] completion in // 클로저이기 때문에 강한참조예방
            guard let self = self else { return }
            switch completion {
            case .finished: // 완료되었을
                print("VM : deleteSelectedUsersWithPublisher : 동시 회원 삭제 :(완료)스트림끊킴❗️")
            case .failure(let failure): // 실패되었을때
                self.handleError(failure)
            }
            
        } receiveValue: { response in
            print("VM / deleteSelectedUsersWithPublisher / \(response)")
        }
        .store(in: &subscriptions)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment