본문 바로가기
iOS_Swift 앱개발👍

[iOS_Swift] Network in iOS (Github API 사용) _ 27

by 개발하는윤기사 2022. 10. 19.
728x90
반응형

 

안녕하세요~ 개발하는 윤기사입니다!!

 

최근 아주 큰 사건이 있었죠...!? 그래서 블로그에 글을 못쓰고 있었습니다^^

 

다시 포스팅하려고 이렇게 왔습니다!

 

오늘 포스팅할 내용은 Network에 관한 내용인데요!

 

1. URLSession

2. Decode Data

3. Fetch Method

 

이렇게 3가지에 대해 알아보겠습니다! 

 

- URL Session - 

 

  • 데이터를 다운로드 혹은 업로드하는 등의 API를 제공해주는 클래스로 URL이 가리키는 Endpoint를 가지고 있다
  • URLSession API를 통해 데이터를 어떻게 전송을 하고 어떻게 동작할지 정책을 설정할 수 있다.
  • 간단하고 기본적인 요청인 경우 동작과 전송에 대한 정책이 기본적으로 설정되어 있는 Shared Session을 사용
  • 별도 처리를 하기 위해서는 Session Configuration 객체를 통한 Session 생성 가능! -> URLSession을 통해 데이터를 다운로드 혹은 업로드할 때, URLSessionConfiguration으로 세부적인 동작과 정책 설정 가능!

- Github API를 이용해서 한 번 실습해보겠습니다!

 

import Foundation

let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)

let url = URL(string: "https://api.github.com/users/Yun-YeoJin")!

//session 생성 후 task 생성, URLSession을 통해 생성되는 개별요청이 task.
let task = session.dataTask(with: url) { data, response, error in
   
   //HTTPURLResponse도 URLResponse 클래스의 서브 클래스.
    guard let httpResponse = response as? HTTPURLResponse, (200..<300).contains(httpResponse.statusCode) else {
        print("---> response \(response)")
        return
    }
    
    guard let data = data else { return } //옵셔널값이라서
    
    let result = String(data: data, encoding: .utf8)
    print(result)
    
}
task.resume()

 

- Decode Data - 

https://ichi.pro/assets/images/max/724/1*3qMQW0PGSMbBge2mhCeC3Q.png

- Github API를 이용해 개발하는 윤기사 정보를 가져와보겠습니다.

- enum CodingKeys: String, CodingKey { } 를 이용하여 API 통신을 통해 받은 결과 값을 원하는 변수로 바꿔줄 수 있습니다.

- 커스텀 키가 필요할 때만 CodingKeys를 작성하면 됩니다.

 

// App Model -> JSON : 인코딩(Incoding)
// JSON -> App Model : 디코딩(Decoding)

import Foundation

struct GithubProfile: Codable {
    let login: String
    let avatarUrl: String
    let htmlUrl: String
    let followers: Int
    let following: Int
    
    enum CodingKeys: String, CodingKey { //매칭을 도와줄 수 있다!
        case login
        case avatarUrl = "avatar_url"
        case htmlUrl = "html_url"
        case followers
        case following
    }
}
// App Model -> JSON : 인코딩(Incoding)
// JSON -> App Model : 디코딩(Decoding)


let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)

let url = URL(string: "https://api.github.com/users/Yun-YeoJin")!

let task = session.dataTask(with: url) { data, response, error in
    
    guard let httpResponse = response as? HTTPURLResponse, (200..<300).contains(httpResponse.statusCode) else {
        print("---> response \(response)")
        return
    }
    
    guard let data = data else { return } 
    //data -> GithubProfile 하고 싶다!
    
    do {
        let decoder = JSONDecoder()
        let profile = try decoder.decode(GithubProfile.self, from: data)
        print("ProFile : \(profile)")
    } catch let error as NSError {
        print("error : \(error)")
        
    }
    
}
task.resume()

 

- Fetch Method - 

 

- 이번엔 네트워크 예외처리를 통해서 코드를 작성해보겠습니다.

- 네트워크 오류 관련된 enum을 하나 만들고, GithubProfile을 담을 Struct를 하나 만듭니다.

- 그 후 API 통신을 하되 성공했을 때와 실패했을 때를 나누겠습니다.

import Foundation

enum NetworkError: Error {
  case invalidRequest
  case transportError(Error)
  case responseError(statusCode: Int)
  case noData
  case decodingError(Error)
}

struct GithubProfile: Codable {
    let login: String
    let avatarUrl: String
    let htmlUrl: String
    let followers: Int
    let following: Int
    
    enum CodingKeys: String, CodingKey {
        case login
        case avatarUrl = "avatar_url"
        case htmlUrl = "html_url"
        case followers
        case following
    }
}

final class NetworkService {
    
    let session: URLSession
    
    init(configuration: URLSessionConfiguration) {
        session = URLSession(configuration: configuration)
    }
    //Result<Success, Failure>
    func fetchProfile(userName: String, completion: @escaping (Result<GithubProfile, Error>) -> Void) {
        
        let url = URL(string: "https://api.github.com/users/\(userName)")!

        let task = session.dataTask(with: url) { data, response, error in
            
            if let error = error { //에러가 있다면
                completion(.failure(NetworkError.transportError(error)))
                return
            }
            
            if let httpResponse = response as? HTTPURLResponse, !(200..<300).contains(httpResponse.statusCode) {
                completion(.failure(NetworkError.responseError(statusCode: httpResponse.statusCode)))
                return
            }
            
            
            guard let data = data else {
                completion(.failure(NetworkError.noData))
                return
            } //옵셔널값이라서
            //data -> GithubProfile 하고 싶다!
            do {
                let decoder = JSONDecoder()
                let profile = try decoder.decode(GithubProfile.self, from: data)
                completion(.success(profile))
                
            } catch let error as NSError {
                completion(.failure(NetworkError.decodingError(error)))
            }
        }
        task.resume()
    }
    
}

// network 담당 NetworkService
// NetworkService를 이용한 네트워크 작업

let networkService = NetworkService(configuration: .default)

networkService.fetchProfile(userName: "Yun-YeoJin") { result in
    switch result {
    case.success(let profile):
        print("ProFile: \(profile)") //성공했을 때는 profile
    case .failure(let error):
        print("ERROR: \(error)") //실패했을 때는 error
    }
}

 

이상 오늘 포스팅은 여기서 마치겠습니다~

 

요새 날씨가 많이 추워졌는데 감기 조심하시고 건강 꼭 잘 챙기세요!!

 

윤기사는 오늘도 빡코딩하겠습니다~^^

728x90
반응형