멀고도 험난한 개발 일지

BeyondUI - 1주차 (HTTP, REST, URLSession, Codable, JSONDecoder ...)

이드entity 2022. 6. 5. 21:10
반응형

먼저 1주차에 공부해야 할 부분들은 아래와 같았다

  • HTTP / REST API
  • URL Session in SwiftUI
  • Async / Await
  • Codable / JSONDecoder
  • WWDC20 - Data Essetial 정리

아직 마지막 영상 정리는 못했고, 나머지 공부한 부분들을 공유하고자 한다!


HTTP / REST API

이전에 웹을 공부하면서도 질리도록 들은 API 이지만
일상 게시판에 잘 찾아보면 알 수 있듯, 항상 껍데기만 만들어왔기 때문에
아직도 API가 뭔지 잘 모르는 상태였다

그래서 다시 정리함!

API

Application Programming Interface

즉, Application에서 어떤 프로그램이 제공하는 기능을 사용할 수 있게 만든 것이다





이번에 새로 시작하는 Challenge를 하면서도 서버를 도입하면서 API를 사용할 것 같은데
이참에 정리하게 돼서 오히려 좋아..


API는 서버에서 제공하고자 하는 데이터나 기능을 원할때 가져다 쓸 수 있도록 제작해둔 것이다

단, 권한이 있는 클라이언트(User)이어야만 제공되는 API도 있다

HTTP

우리가 브라우저에 접속할 때마다 자주 보는 알파벳들..
그래서 HTTP가 뭔데?

Hyper Text Transfer Protocol

인터넷에서 리소스를 주고 받을 수 있도록 해주는 Protocol(규칙)이다

HTTP를 따르는 통신 방식을 HTTP Method라고 하는데
상당히 다양한 Method들이 있다

그 중 일단은 자주 쓰일 POST와 GET만 보자..!

  • POST - 서버로 데이터를 전송
  • GET - 특정 리소스를 서버로부터 가져옴

영어 그대로 POST(= 게시하다)는 서버에 데이터를 게시한다고 생각하면 될 것 같고

GET(= 가져오다)도 서버로부터 데이터를 가져온다고 보면 될 듯 하다

추가로 다른 Method들은 아래와 같이 다양하기 때문에

궁금하다면 스스로 찾ㅇ...

HTTP 통신 과정

위 그림과 같이, HTTP 통신 과정은 두가지로 나뉜다.

HTTP Request

웹 브라우저의 URL을 통해 어느 웹사이트의 어느 경로의 페이지를 요청할지 나타내는 것

사실 HTTP Request에 관해 작성하려면 끝도 없기 때문에
일단 대략적인 개념만 보고 넘어가자...
사실 저도 아직은 잘 몰ㄹ...

HTTP Response

HTTP Request를 통해 요청된 정보에 대해 웹서버가 클라이언트에 보내는 응답형식과 결과

HTTP Response는 Request처럼 넘어가기 전에
Status Line에 대해서만 알아보자

Response가 오면 제대로 된 응답이 됐는지
상태를 보여주는 세 자리수 숫자이고 아래와 같이 나뉜다

 

  • 1xx : Informational
    • 요청을 클라이언트에서 성공적으로 수신했음
    • 서버 끝에서 처리 중임
  • 2xx : Success
    • 서버가 요청을 성공적으로 받았고 처리도 함
  • 3xx : Redirection
    • 자동으로 다른 URL로 리디렉션 함
  • 4xx : Client Error
    • 서버가 해결할 수 없는 클라이언트 측 에러
  • 5xx : Server Error
    • 서버가 클라이언트의 요청을 처리하지 못함

HTTP Request Parameter

HTTP를 통해 어떤 요청을 보낼 때 필요한 Parameter 들이 있다

형태는 아래와 같다

<Scheme>://<id>:<pw>@<Hostname>:<Port>/(path)?<Query String>$<Query String>..#<Fragment>

눈치 빠른 사람들은 위에 형태가 URL 형태랑 비슷함을 알 수 있을거다!
요소 하나하나 어떤 역할이냐 하면...

  • <Scheme>
    • 컴퓨터 간 정보를 주고받을 때 통신 방법에 대한 규칙으로, HTTP, HTTPS 등이 들어감
  • <id>:<pw>
    • 특정 서버는 서버의 데이터에 접근할 때 아이디와 패스워드를 요구함
    • 하지만 서버의 데이터가 공개된 데이터인 경우 입력하지 않아도 됨😉
  • <Hostname>:<Port>
    • 해당 웹 서버로 접근하기 위해 서버의 IP(또는 Hostname)에 접근
    • 각 서버는 매우 많은 포트가 존재하고, 특정 웹페이지에 접근하기 위해서는 지정된 포트를 입력해야 함..!
    • 보통 HTTP는 80번 포트 / HTTPS는 443번 포트
  • (path)
    • 호스트 서버에서 제공하는 자원의 실질적인 경로
  • <Query String>$<Query String>
    • 위에 전체 형태에서 ?에서 #사이의 구간을 parameter라고 함
    • 이 구간에서는 Query String이라는 질의문을 수행함
      • 여기서 Query String 이란 DB에 직접 SQL문을 날려 결과값을 받는 것!
  • <Fragment>
    • 페이지의 특정 요소 지정 가능함

REST API

REST란?

REpresentational State Transfer

웹 서비스의 구조를 만드는 데 활용되는 패턴

  • HTTP를 잘 활용하기 위한 원칙
  • CRUD 메소드, HTTP 메소드 중 POST, GET, PUT, DELETE 만 사용
  • URI로 자원을 표현
    • URI - 특정 리소스를 식별하는 통합 자원 식별자
    • URL을 포함하는 개념
    • URI는 식별, URL은 위치를 알려줌

REST의 4가지 속성

REST가 되기 위해서는 몇가지 속성을 만족해야 하는데, 아래와 같다

  • 서버의 모든 resource는 클라이언트가 바로 접근할 수 있는 고유 URL이 존재
  • 모든 Request는 클라이언트가 요청할 때마다 필요한 정보를 주기 때문에 세션 정보를 보관할 필요 없음
  • HTTP 메소드를 사용 → Resource는 HTTP Method인 GET, POST, PUT, DELETE
  • 서비스 내의 하나의 Resource가 주변에 연관된 리소스들과 연결되어 표현이 돼야 함

 


URL Session

공식문서 정의

An object that coordinates a group of related, network data transfer tasks

 

용도

URL로 표기되는 곳에서 데이터를 다운로드 및 업로드 할 수 있는 API를 제공

애플에서 제공하는 앱과 서버 간의 데이터를 주고받기 위한 API라 생각하면 될 듯?!

URL Session을 사용하면 여러 Protocol과 Authentication, Cache와 Cookie 관리 등을 할 수 있음

URL Session 기본 설정으로 사용하기

  1. URLSessionConfiguration 생성
let config = URLSessionConfiguration.default // default, ephemeral, background 사용 가능
let session = URLSession(configuration: config)

직접 URLSession을 사용해보니, 위와 같이 default로 설정할거면 굳이 이 코드를 작성할 필요가 없었다

그렇다면 configuration으로는 어떤게 있을까

  • default - 기본 통신
  • ephemeral - 쿠키나 캐시를 저장하지 않도록 정책을 가져가는 통신
  • background - 앱이 백그라운드에 있는 상황에서 다운로드/업로드 할 수 있도록 함
  1. URLComponents 생성하여 query 설정
var urlComponents = URLComponents(
string: "https://ids-identity-project.tistory.com/search/users?"
let urlIDQuery = URLQueryItem(name:"Id", value:"123")
let urlAgeQuery = URLQueryItem(name:"age", value:"20")
urlComponents?.queryItems?.append(userIDQuery)
urlComponents?.queryItems?.append(ageQuery)

이것도 이론만 공부할때는 몰랐고, 직접 해보니 알게 된 부분이다


위 코드를 보면 URLComponents()를 사용하여 변수를 만들었는데, 이렇게 하면 URL()로 만든것과 차이점이 생긴다


3번째 단계 코드를 잘 보면 첫번째 줄에 urlComponents?.url이 되어 있는걸 볼 수 있는데, 엄연히 URLComponent와 URL은 다른 것이기 때문에 URL을 사용하려면 URLComponent를 URL로 전환해주는 과정이 필요하다


그러면 굳이 왜 한번 더 전환해야 하는데 URLComponent를 사용할까?


Query문을 추가하기 쉬워지기 때문..!
결국 JSON 형태의 데이터를 가져올 때 Query문으로 어떤 데이터를 가져올지 지정을 해야할텐데 그냥 URL에서는 하기 번거로운걸 URLComponent에서는 쉽게 추가할 수 있다!!


위 코드와 같이 그냥 append만 해도 되고


필요한 Query문을 Array 형식으로 저장하고, queryItems로 넣을수도 있다

let urlNumberQuery = [URLQueryItem(name: "number", value: "\(number)")]

urlComp.queryItems = urlNumberQuery

 

  1. URLComponents와 URLSession을 이용하여 Task 생성
guard let requestURL = urlComponents?.url else { return }
let dataTask = session.dataTask(with: requestURL) { (data, response, error) in

    // error가 존재하면 종료
    guard error == nil else { return }

    // status 코드가 200번대여야 성공적인 네트워크라 판단
    let successsRange = 200..<300
    guard let satusCode = (response as? HTTPURLResponse)?.statusCode,
          successsRange.contains(statusCode) else { return }

    // response 데이터 획득, utf8인코딩을 통해 string형태로 변환
    guard let resultData = data else { return }
    let resultString = String(data: resultData, encoding: .utf8)
    print(resultData)
    print(resultString)
}

dataTask.resume()

마지막으로 해당 Session에서 어떤 Task를 수행할지 지정하고, 해당 Task에서 수행할 코드를 작성해주면 된다

Task 생성 후 실행할 코드는 주석으로 설명을 뒀으니 자세한 설명은 생략..

사실 이 부분은 더 공부가 필요..

 


Async / Await

먼저 나도 synchronous와 asynchronous가 뭔지 잘 몰랐기 때문에..
간략하게 설명을 두겠다

Synchronous

→ Thread에서 주어진 task만 처리 가능

 

Asynchronous

→ Thread에서 주어진 task를 실행하면서 다른 task도 병행

→ 주어진 task를 완료하면 completionHandler 등이 알려줄 수 있음

Async

공식문서 정의

Schedules a work item for immediate execution, and returns immediately

"Enables a function to suspend"
함수를 유예할 수 있게 만들어줌

Await

"Marks where an async function may suspend execution"
Async 함수가 어디에서 유예할 가능성이 있는지 마크해줌

사실 async / await 모두 개념적으로는 이해가 어느정도 됐는데
실제로 코드에서 쓰라고 하면 어떻게 써야할지 모르겠다..

추가 궁금증

URLSession.dataTask(
    with: URLRequest, 
    completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void
)
URLSession.data(with: URLRequest) async throws -> (Data, URLResponse)

공식 영상을 보면 completion handler를 async / await로(위 코드에서 아래 코드로) 간략화 시킬 수 있는걸 강조하는데
completion handler는 말 그대로 어떤걸 마치고 나서 실행시킬 코드가 아닌가..!
하지만 async/await는 비동기처리에 사용되는것 같은데 이 두가지가 어떻게 연관이 되는지...

이 부분은 추가로 공부를 해보면서 알아봐야하지 않을까 싶다🤔


JSONDecoder / Codable

JSONDecoder

공식문서 정의

An object that decodes instances of a data type from JSON objects

→ JSON 형식의 struct에는 Codable Protocol이 포함되어야지 Decoding 가능

Codable 및 JSONDecoder를 사용한 예시

struct GroceryProduct: Codable {
    var name: String
    var points: Int
    var description: String?
}

let json = """
{
    "name": "Durian",
    "points": 600,
    "description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!

let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)

print(product.name) // Prints "Durian"

Codable

공식문서 정의

A type that can convert itself into and out of an external representation

→ Encodable과 Decodable 모두를 아우르는 Protocol
단, Encoding과 Decoding 둘 중 하나만 필요한 경우에는 Codable보다는 하나만 사용하기..!

Codingkey

Codable 인스턴스가 Encoding 또는 Decoding 될 때
필수로 필요한 property를 enum 형식으로 지정해둠

반대로, 필수로 필요한 property가 아니라면
Codingkey에서 제외하여 필수가 아님을 표시할 수 있음

→ JSON 파일을 Decoding 할 때 key 값이 매치되지 않는 경우가 생기면,
Codingkey Protocol을 사용해 해결 가능!

코드 예시

let jsonString = """
{
"name" : "Zedd",
"age" : 100,
"**birth_date**" : "2017-01-22T23:16:50+0000"
}
"""

struct Person: Codable {
    var name: String
    var age: Int
    var birthday: Date    
}

위와 같은 경우, birthday라는 key가 없다는 오류 발생하는데,

이런 경우에 Codingkey를 enum으로 추가하면 해결..!

struct Person: Codable {
    var name: String
    var age: Int
    var birthday: Date    

    enum CodingKeys: String, CodingKey {
        case name
        case age
        case birthday = "birth_day"
    }
}

추가로, 이렇게 하면 JSON 파일의 birth_day라는 key는
Codingkeys의 birthday key와 매치됨!

 


참고자료

URLSession
Apple Developer Documentation

[Swift] URLSession과 사용법

[iOS - swift] URLSession 네트워크 통신 기본 (URLSessionConfiguration, URLSession, URLComponents, URLSessionTask)

 

JSONDecoder
https://www.youtube.com/watch?v=CimY_Sr3gWw

 

Codable
Apple Developer Documentation

 

반응형