๊ธฐํƒ€/iOS๐ŸŽ

[iOS] ์„œ๋ฒ„ํ†ต์‹  ์—ฐ๊ฒฐํ•˜๊ธฐ

yujindonut 2022. 5. 10. 17:15
728x90

1. API ๋ช…์„ธ์„œ ํ™•์ธํ•˜๊ธฐ

2. PostMan ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ

 

Response ํ˜•ํƒœ๋ฅผ ์ง์ ‘ ํ™•์ธํ•˜๊ธฐ 

 

์„ฑ๊ณต - 200 ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต

์‹คํŒจ - 409 Duplicate : ํ•ด๋‹น ์ •๋ณด๊ฐ€ ์žˆ์„๋•Œ

์„œ๋ฒ„ ํ†ต์‹  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์ „ ์‚ฌ์ „ ์ค€๋น„ ๊ณผ์ •

3. HTTP ํ†ต์‹ ์„ ์œ„ํ•œ plist ์„ค์ • (http ์„œ๋ฒ„๋กœ ํ†ต์‹ ์„ ์‹œ๋„ํ•˜๋Š” ๊ฒฝ์šฐ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋จ! https๋Š” ์•ˆํ•ด์ค˜๋„ ๋จ)

๋ณดํ†ต์€ http ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. Apple ์ธก์—์„œ ์•ฑ ์ž์ฒด์˜ ๋ณด์•ˆ์„ฑ์„ ์œ„ํ•ด์„œ ATS(App Transport Security)๋ผ๋Š” ์ •์ฑ…์„ ํ†ตํ•ด ๊ธฐ๋ณธ์ ์œผ๋กœ https ํ†ต์‹ ์„ ํ•˜๋„๋ก ์œ ๋„ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ! 

 

4. APIConstants.swift ์ž‘์„ฑ : API ์ฃผ์†Œ๋ฅผ ๋ชจ์•„ ๋†“์€ ํŒŒ์ผ

์ž์› (์œ„์น˜, ์–ด๋””์—) : URI

Base URL๊ณผ ๋‚˜๋จธ์ง€ ๊ฒฝ๋กœ๋ฅผ ๋‚˜๋ˆ„์–ด ๊ด€๋ฆฌํ•˜๋ฉด ํŽธํ•จ!

ํ–‰์œ„ ( ์–ด๋–ค ๊ฒƒ์„ ํ•  ๊ฒƒ์ธ์ง€ ) : HTTP Method

ํ‘œํ˜„, ๋ฉ”์„ธ์ง€ (์ด๋Ÿฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋‹ค) : JSON

5. NetworkResult.swift ์ž‘์„ฑ ( ์„œ๋ฒ„ ํ†ต์‹  ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•  ์—ด๊ฑฐํ˜• )

์„œ๋ฒ„ ํ†ต์‹  ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํŒŒ์ผ

์„œ๋ฒ„ํ†ต์‹ ์„ ํ• ๋•Œ ๋ฐ‘์˜ ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜๋ฉด๋จ

6. ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ์ƒ์„ฑ ( ์„œ๋ฒ„ํ†ต์‹ ์œผ๋กœ ๋ฐ›์€ JSON ๋ฐ์ดํ„ฐ๋ฅผ Swift๋กœ ๋ฐ”๊ฟ€ ๊ตฌ์กฐ์ฒด ๋ชจ๋ธ)

- ๋„˜๊ฒจ ๋ฐ›์€ JSON์„ Swift ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ์ž˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก Data Model์„ ์ƒ์„ฑ

- ๊ธฐ๋ณธ์ ์œผ๋กœ ๋„คํŠธ์›Œํฌ ํ†ต์‹ ๊ฒฐ๊ณผ๋กœ ๋„˜์–ด์˜ค๋Š” JSON ๋ฐ์ดํ„ฐ๋ฅผ ์•ฑ์ด ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก swift ๋ฐ”๊พธ์–ด์•ผํ•จ ( decode ๊ณผ์ • )

 

Encodable, Decodable ํ”„๋กœํ† ์ฝœ์„ ๋ฌถ์€ ๊ฒƒ = Codable์„ ์‚ฌ์šฉํ•˜๋ฉด ๋จ!

๋”ฐ๋กœ ๋‘๊ฐœ์˜ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜์ง€ ์•Š์•„๋„ ๋จ

Encodable : ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์„ Encodeํ•ด์„œ data(JSON)์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋ ค๋ฉด Encodable์ด๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด์•ผํ•จ

Decodable : data(JSON)์„ Decodeํ•ด์„œ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ๋กœ ๋งŒ๋“œ๋ ค๋ฉด Decodable์ด๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด์•ผํ•จ

๋ฐ์ดํ„ฐ ๋ถ€๋ถ„์ด ์˜ต์…”๋„์ธ ์ด์œ  : ๋กœ๊ทธ์ธ์ด ์„ฑ๊ณตํ• ๋•Œ๋Š” data๊ฐ€ ๋„˜์–ด์˜ค๊ณ , ์‹คํŒจํ–ˆ์„ ๋•Œ๋Š” data๊ฐ€ ์•ˆ๋„˜์–ด์˜ค๊ธฐ ๋•Œ๋ฌธ!

 

7. Service(Request - Response) ์ฝ”๋“œ ์ž‘์„ฑ

: (Request๋ฅผ ๋งŒ๋“ค๊ณ  ๋ณด๋‚ธ ํ›„ Response๋ฅผ ๋ฐ›๊ณ  ํ•ด๋…ํ•˜๋Š” ์„œ๋ฒ„ ํ†ต์‹ ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค )

import Foundation
import Alamofire
//(1) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€

class UserService {
    
    static let shared = UserService()
//(2)์‹ฑ๊ธ€ํ†ต ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•ด์„œ ์•ฑ ์–ด๋””์—์„œ๋“ ์ง€ ์ ‘๊ทผ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•œ๋‹ค
    private init() {}
    
    func login(name: String, email: String, password: String, completion: @escaping(NetworkResult<Any>) -> Void)
    {
        let url = APIConstants.loginURL //ํ†ต์‹ ํ•  API ์ฃผ์†Œ
        
        //HTTP Headers : ์š”์ฒญ ํ—ค๋”
        let header : HTTPHeaders = ["Content-Type" : "application/json"]
        
        //์š”์ฒญ ๋ฐ”๋””
        let body : Parameters = [
            "name" : name,
            "email" : email,
            "password" : password
        ]
        
        //์š”์ฒญ์„œ //Request ์ƒ์„ฑ
        //ํ†ต์‹ ํ•  ์ฃผ์†Œ, HTTP๋ฉ”์†Œ๋“œ, ์š”์ฒญ๋ฐฉ์‹, ์ธ์ฝ”๋”ฉ๋ฐฉ์‹, ์š”์ฒญํ—ค๋”
        let dataRequest = AF.request(url,
                                    method: .post,
                                    parameters: body,
                                    encoding: JSONEncoding.default,
                                    headers: header)
                                    
        //request ์‹œ์ž‘ ,responseData๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ๋ฐ์ดํ„ฐ ํ†ต์‹  ์‹œ์ž‘ 
        dataRequest.responseData{
            response in //๋ฐ์ดํ„ฐ ํ†ต์‹ ์˜ ๊ฒฐ๊ณผ๊ฐ€ response์— ๋‹ด๊ธฐ๊ฒŒ ๋œ๋‹ค
            switch response.result {
            case .success: //๋ฐ์ดํ„ฐ ํ†ต์‹ ์ด ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ์— 
                guard let statusCode = response.response?.statusCode else {return}
                guard let value = response.value else {return}
                
                let networkResult = self.judgeStatus(by: statusCode, value)
                completion(networkResult)
            case .failure:
                completion(.networkFail)
            }
        }
    }
    private func judgeStatus(by statusCode: Int, _ data: Data) -> NetworkResult<Any> {
        switch statusCode {
        case ..<300 : return isVaildData(data: data) 
        case 400..<500 : return .pathErr
        case 500..<600 : return .serverErr
        default : return .networkFail
        }
    }
    //ํ†ต์‹ ์ด ์„ฑ๊ณตํ•˜๊ณ  ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋“ค์–ด์™”์„๋•Œ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜
    private func isVaildData(data: Data) -> NetworkResult<Any> {
        let decoder = JSONDecoder() //์„œ๋ฒ„์—์„œ ์ค€ ๋ฐ์ดํ„ฐ๋ฅผ Codable์„ ์ฑ„ํƒ
        guard let decodedData = try? decoder.decode(LoginResponse.self, from: data)
        //๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ™˜์ด ๋˜๊ฒŒ๋” Response ๋ชจ๋ธ ๊ตฌ์กฐ์ฒด๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•ด์„œ ๋„ฃ๊ณ , ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ NetworkResult Success ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ
        else { return .pathErr }
        
        return .success(decodedData as Any)
    }
}

 

8. Service(Request - Response) ์ฝ”๋“œ ํ˜ธ์ถœ

: ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ ( ์„œ๋ฒ„ ํ†ต์‹ ์ฝ”๋“œ๋ฅผ ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ํ˜ธ์ถœ)

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var nameTextField: UITextField!
    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }

    // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ๋กœ๊ทธ์ธ ์„œ๋ฒ„ ํ†ต์‹  ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
    @IBAction func loginButtonTapped(_ sender: Any) {
        print("๋กœ๊ทธ์ธ")
        login()
    }
}

extension ViewController {
    
    // ์„œ๋ฒ„ ํ†ต์‹  ์ฝ”๋“œ๋ฅผ ์‹ค์ œ๋กœ ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ํ˜ธ์ถœํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.
    func login() {
        
        // ๊ฐ๊ฐ์˜ ํ…์ŠคํŠธ ํ•„๋“œ์˜ ์žˆ๋Š” ๊ฐ’์„ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค.
        guard let name = nameTextField.text else { return }
        guard let email = emailTextField.text else { return }
        guard let password = passwordTextField.text else { return }
        
        // ์„œ๋ฒ„ ํ†ต์‹  ์„œ๋น„์Šค ์ฝ”๋“œ๋ฅผ ์‹ฑ๊ธ€ํ†ค ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด์„œ ์ ‘๊ทผํ•˜๊ณ  ์žˆ๋„ค์š”.
        // ํ˜ธ์ถœ ํ›„์— ๋ฐ›์€ ์‘๋‹ต์„ ๊ฐ€์ง€๊ณ , ์ ์ ˆํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
        UserService.shared.login(
            name: name,
            email: email,
            password: password) { response in
            switch response {
            case .success(let data):
                guard let data = data as? LoginResponse else { return }
                print(data)
                self.alert(message: data.message)
            case .requestErr(let err):
                print(err)
            case .pathErr:
                print("pathErr")
            case .serverErr:
                print("serverErr")
            case .networkFail:
                print("networkFail")
            }
        }
    }
    
    // ์•Œ๋ฆผ์ฐฝ์„ ๋„์šฐ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
    func alert(message: String) {
        let alertVC = UIAlertController(title: message, message: nil, preferredStyle: .alert)
        let okAction = UIAlertAction(title: "ํ™•์ธ", style: .default, handler: nil)
        alertVC.addAction(okAction)
        present(alertVC, animated: true)
    }
}

์ด์ •๋ฆฌ

์ถœ์ฒ˜ : SOPT30 - ๊น€ํƒœํ˜„ ํŒŒํŠธ์žฅ๋‹˜ 4์ฃผ์ฐจ ์„ธ๋ฏธ๋‚˜

์ถœ์ฒ˜ :SOPT30 - ๊น€ํƒœํ˜„ ํŒŒํŠธ์žฅ๋‹˜ 4์ฃผ์ฐจ ์„ธ๋ฏธ๋‚˜

728x90