VesselWheel

Swift에서의 네트워크 통신 이해하기(.feat URL Session)(1/2) 본문

Xcode Study

Swift에서의 네트워크 통신 이해하기(.feat URL Session)(1/2)

JasonYang 2024. 1. 4. 17:57

아직은 생소하지만 개발자로서 앱을 개발하려면 데이터를 스왑하기 위해? 네트워크 통신을 통해 다양한 API에서 데이터를 가져와야한다. 

따라서 swift에서 다루는 URL, REST API, Decodable/Encodable/Codable에 대한 개념을 이해하고 데이터 모델링을 숙달하고자 한다. 

URLSession을 통해 REST API와 통신할 수 있다. 

URL 구성요소

URL 구성요소란?

더보기
각 구성요소들은 API 엔드포인트와 함께 특정 자원에 대한 요청을 식별하고 전달하는 데 사용됩니다.

### **프로토콜 (Protocol)**

URL은 일반적으로 **`http://`** 또는 **`https://`**와 같은 프로토콜로 시작합니다.
이는 클라이언트와 서버 간의 통신 방법을 지정합니다. 
**`http://`**는 보안 없는 통신을, **`https://`**는 SSL/TLS 암호화를 사용하여 보안된 통신을 나타냅니다.

### **도메인 (Domain)**

도메인은 API 서버가 호스팅되는 서버의 주소를 나타냅니다.
예를 들어, **`api.example.com`**은 API 서버가 위치한 서버의 도메인 주소입니다.

### **포트 (Port, 옵션)**

포트 번호는 서버에서 API 요청을 수신하는데 사용되는 포트를 나타냅니다.
대부분의 경우 HTTP의 기본 포트는 80이고, HTTPS의 기본 포트는 443입니다.
일반적으로 생략될 수 있습니다.

### **경로 (Path)**

경로는 서버에서 요청된 자원이나 서비스의 위치를 나타냅니다.
예를 들어, **`/users`** 경로는 사용자 자원에 대한 요청을 나타냅니다.
경로는 엔드포인트와 연관되어 특정 자원이나 서비스를 식별합니다.

### **쿼리 매개변수 (Query Parameters, 옵션)**

쿼리 매개변수는 URL에 추가 정보를 전달하는데 사용됩니다. 
예를 들어, **`?page=2&sort=desc`**와 같이 사용자가 원하는 페이지 번호나 정렬 방법을 서버에 전달할 수 있습니다.

 

REST API 개념 이해하기

REST는 HTTP 프로토콜을 기반으로 하며, 클라이언트와 서버 간의 통신을 위한 규칙을 정의합니다.

HTTP 메서드 (HTTP Methods)

REST API에서는 HTTP 메서드를 사용하여 자원을 다룹니다. 가장 널리 사용되는 HTTP 메서드는 다음과 같습니다.

  • GET: 자원을 읽기 위해 사용됩니다. | (ex. 유저를 조회합니다.)
  • POST: 새로운 자원을 생성하기 위해 사용됩니다. - 멱등하지 않음 | (ex. 유저를 생성(가입)합니다.)
  • PUT: 기존 자원을 업데이트하기 위해 사용됩니다. - 멱등함 | (ex. 유저를 수정합니다.)
  • DELETE: 자원을 삭제하기 위해 사용됩니다. | (ex. 유저를 삭제(탈퇴)합니다.)

* 멱등성: 여러번 요청(시도) 해도 모든 결과값이 동일한 성질

자원 (Resources)

REST API에서는 모든 데이터가 자원으로 표현됩니다. 이러한 자원은 고유한 식별자(일반적으로 URI로 표현)를 갖고 있습니다. 예를 들어, 웹 사이트의 사용자 프로필, 글, 이미지, 동영상 등은 각각의 자원으로 표현될 수 있습니다.

URI (Uniform Resource Identifier)

자원은 고유한 식별자인 URI를 갖습니다. URI는 자원을 찾을 수 있는 주소를 나타냅니다. 예를 들어, 웹 사이트의 사용자 프로필을 나타내는 URI는 **https://example.com/users/123**과 같이 표현될 수 있습니다.

URL과 URI의 차이

더보기

URL과 URI의 차이: URI는 리소스를 식별하기 위한 일반적인 용어이며, URL은 리소스의 위치를 나타내는 구체적인 형태의 URI라는점에서 두 개념의 차이가 있습니다.

표현 (Representations)

자원의 상태는 여러 형식으로 표현될 수 있습니다. 일반적으로는 JSON 형식을 사용하여 데이터를 표현합니다. 클라이언트와 서버 간의 통신은 이러한 표현을 통해 이루어집니다.

연결 (Stateless Communication)

REST API는 클라이언트와 서버 간의 통신을 위해 연결을 유지하지 않습니다. 각 요청은 독립적으로 처리됩니다.

 

JASON 데이터 형식


URLSession 이해하기

URLSession은 네트워크 데이터를 가져오거나 보내는 작업을 수행합니다.

URLSession의 주요 특징

  • 비동기적 네트워킹 (Asynchronous Networking) URLSession은 비동기적으로 네트워크 요청을 처리하므로, 네트워크 작업이 백그라운드에서 수행될 수 있습니다. 이는 앱의 성능을 향상시키고 응답성을 유지하는 데 도움이 됩니다.
  • 다양한 데이터 전송 방식 지원 URLSession을 사용하여 데이터를 업로드하거나 다운로드할 수 있으며, JSON, 이미지, 파일 등 다양한 데이터 형식을 처리할 수 있습니다. 이번 숙련 챕터에서의 예제는 JSON 데이터를 다운로드하여 사용합니다.
  • 캐시와 쿠키 관리 URLSession은 네트워크 응답을 캐싱하고 쿠키를 관리할 수 있는 기능을 제공합니다.

비동기화 참조 글 : https://vesselwheel.tistory.com/153

 

클로저로 만드는 타이머 매서드

들어가기 앞서, 타이머 기능을 위해서는 클로저의 탈출 클로저(Esacaping closure)의 비동기 실행에 대한 이해가 필요하다. 탈출 클로저(Esacaping closure) 란? 더보기 코드의 순차적 실행과 비동기의 실

vesselwheel.tistory.com

 

Get 예시

더보기
// URLSession 인스턴스 생성
let session = URLSession.shared // sharde 속성을 사용하여 인스턴스 생성

// URL 생성
if let url = URL(string: "https://api.example.com/data") {
    // URLSessionDataTask를 사용하여 비동기적으로 데이터 요청
    /***
     URLSessionDataTask는 비동기적으로 데이터를 요청하고 응답을 받기 위해 사용하는 객체입니다. dataTask(with:completionHandler:) 메서드를 사용하여 데이터를 요청하고, 요청이 완료될 때 호출될 completion handler를 정의합니다.
    */
    let task = session.dataTask(with: url) { (data, response, error) in
        /***
         completion handler에서는 요청이 완료된 후 호출되며, 에러가 발생했는지 확인하고 데이터를 받아올 수 있습니다. 받아온 데이터를 이후에 처리하는 로직을 작성하면 됩니다.
         이 코드는 주어진 URL("https://api.example.com/data")에 데이터를 요청하고, 응답으로 받은 데이터를 출력하는 예제입니다.
         */
        if let error = error {
            print("Error: \(error)")
        } else if let data = data {
            // 데이터를 받아온 후 처리하는 로직을 작성
            print("Received data: \(data)")
        }
    }
    
    // 네트워크 요청 시작 -> task.resume() resume() 메서드를 호출하여 네트워크 요청을 시작합니다. 이때 비동기적으로 데이터를 요청하고 응답을 받게 됩니다.
    task.resume()
}

 

 

URLRequest를 사용한 POST 예시

더보기
// URLSession 인스턴스 생성
let session1 = URLSession.shared

// URL 생성
if let url = URL(string: "https://api.example.com/data") {
  // URLSessionDataTask를 사용하여 비동기적으로 데이터 요청
  
  // URLRequest 생성
  var request = URLRequest(url: url)
  
  // HTTP 메서드 설정 (POST)
  request.httpMethod = "POST" // GET / PUT / DELETE 사용 가능

  // HTTP 헤더 설정
  request.addValue("application/json", forHTTPHeaderField: "Content-Type")
  
  // HTTP Body에 보낼 데이터 설정 (JSON 형식)
  let parameters: [String: String] = [
    "value1": "example value",
    "value2": "example value"
    // 추가적인 필요한 데이터 추가 가능
  ]
  
  // HTTP Body에 JSON 데이터 설정
  request.httpBody = try? JSONEncoder().encode(parameters)
  
  let task = session1.dataTask(with: request) { (data, response, error) in
    if let error = error {
      print("Error: \(error)")
    } else if let data = data {
      // 데이터를 받아온 후 처리하는 로직을 작성
      print("Received data: \(data)")
    }
  }
  
  // 네트워크 요청 시작
  task.resume()
}