1. URL 구성요소의 이해
각 URL 구성요소들은 API 엔드포인트와 함께 특정 자원에 대한 요청을 식별하고 전달하는 데 사용
1-1. 프로토콜 (Protocol)
URL은 일반적으로 'http://' 또는 'https://'와 같은 프로토콜로 시작 ↓ 클라이언트와 서버 간의 통신 방법을 지정 |
'http://'는 보안 없는 통신을, 'https://'는 'SSL/TLS 암호화'를 사용, 보안된 통신을 나타냄 |
1-2. 도메인 (Domain)
도메인은 API 서버가 호스팅되는 서버의 주소를 나타냄
(예시로, 'api.example.com' 은 API 서버가 위치한 서버의 도메인 주소)
1-3. 포트 (Port, 옵션)
포트 번호 = 서버에서 API 요청 수신에 사용되는 포트 |
대부분의 경우 HTTP 기본 포트 = 80 HTTPS 기본 포트 = 443 ↓↓↓ 일반적으로 생략될 수 있음 |
1-4. 경로 (Path)
서버에서 요청된 자원이나 서비스의 위치
예를 들어, /users 경로는 사용자 자원에 대한 요청
'엔드포인트'와 연관되어 특정 자원이나 서비스를 식별
1-5. 쿼리 매개변수 (Query Parameters, 옵션)
URL 추가 정보 전달에 사용
예시로, "?page=2&sort=desc"와 같이 사용자가 원하는 페이지 번호 혹은 정렬 방법을 서버에 전달 가능
2. REST API 의 개념
REST는 HTTP 프로토콜 기반,
클라이언트 ↔ 서버 간의 통신을 위한 규칙 정의
2-1. HTTP 메서드 (HTTP Methods)
HTTP 메서드를 사용 → 자원을 다룸
[가장 널리 사용되는 HTTP 메서드]
GET(갯)
자원을 읽기 위해 사용
(ex. 유저를 조회합니다.)
POST(포스트)
새로운 자원을 생성하기 위해 사용
멱등 X (ex. 유저를 생성(가입)합니다.)
쉽게 말해 수정 불가
PUT(풋)
기존 자원을 업데이트하기 위해 사용
멱등 O (ex. 유저를 수정합니다.)
쉽게 말해 수정 가능
DELETE(딜리트)
자원을 삭제하기 위해 사용
(ex. 유저를 삭제(탈퇴)합니다.)
멱등, 멱등성 : 여러번 요청(시도) 해도 모든 결과값이 동일한 성질
2-2. 자원 (Resources)
모든 데이터가 자원으로 표현
자원은 고유 식별자(일반적으로 URI로 표현)를 갖는다.
ex) 웹 사이트의 사용자 프로필, 글, 이미지, 동영상 등은 각각의 자원으로 표현됨.
2-3. URI (Uniform Resource Identifier)
자원은 고유한 식별자인 URI를 갖는다.
URI는 자원을 찾을 수 있는 주소다.
ex) 웹 사이트 사용자 프로필을 나타내는 URI는 "https://example.com/users/123"과 같이 표현가능
URL과 URI의 차이:
URI는 리소스를 식별하기 위한 일반적인 용어,
URL은 리소스 위치를 나타내는 구체적 형태다.
2-4. 표현 (Representations)
자원의 상태는 여러 형식으로 표현가능
일반적으로 JSON 형식 사용 → 데이터 표현
클라이언트, 서버 간 통신은 이와 같은 표현을 통해 이루어짐
2-5. 연결 (Stateless Communication)
클라이언트, 서버 간의 통신을 위해 연결 유지X
각 요청 = 독립적으로 처리
3. URLSession의 이해
'URLSession'은 네트워크 데이터를 가져오거나 보내는 작업을 수행
3-1. URLSession의 주요 특징
비동기적 네트워킹 (Asynchronous Networking) |
다양한 데이터 전송 방식 지원 | 캐시와 쿠키 관리 |
비동기적 네트워크 요청을 처리 ↓ 네트워크 작업이 백그라운드에서 수행 가능 ↓ 앱의 성능을 향상, 응답성을 유지 |
데이터 업로드 및 다운로드 가능 | 네트워크 응답을 캐싱 ↓ 쿠키 관리 기능 제공 |
JSON, 이미지, 파일 등 다양한 데이터 형식을 처리 가능 |
||
JSON 데이터를 다운로드하여 사용 |
// GET 예시
import Foundation
// URLSession 인스턴스 생성
let session = URLSession.shared
// URL 생성
if let url = URL(string: "https://api.example.com/data") {
// URLSessionDataTask를 사용하여 비동기적으로 데이터 요청
let task = session.dataTask(with: url) { (data, response, error) in // response의 경우 통신응답에 의한 검증코드를 의미
if let error = error {
print("Error: \(error)")
} else if let data = data {
// 데이터를 받아온 후 처리하는 로직을 작성
print("Received data: \(data)")
}
}
// 네트워크 요청 시작
task.resume()
}
// URLRequest를 사용한 POST 예시
import Foundation
// URLSession 인스턴스 생성
let session = 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 = session.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()
}
4. Decodable(디코더블), Encodable(엔코더블), Codable(코더블)의 이해
4-1. Decodable(디코더블) 프로토콜
데이터 → 객체로 디코딩할 때 사용
(즉, 외부 데이터(JSON)를 Swift의 데이터 모델 변환에 필요한 프로토콜)
"Decodable(디코더블)"을 준수하는 객체 → 외부 데이터를 해석 및 데이터를 객체의 프로퍼티로 매핑 가능해야 함
CodingKeys(코딩키즈) → 디코딩 할 때, 프로퍼티들에 대한 매핑을 제공하는 역할 (아래 예시 참고)
// id 라는 프로퍼티의 디코딩 키를 key로, name 프로퍼티의 디코딩 키를 프로퍼티 이름과 동일하게 지정한 예시
struct User: Decodable {
let id: Int
let name: String
// 다른 프로퍼티들...
public enum CodingKeys: String, CodingKey {
case id = "key"
case name
}
// Decoding - 디코딩
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
}
}
4-2. Encodable(엔코더블) 프로토콜
객체 → 데이터로 인코딩할 때 사용
(즉, Swift의 데이터 모델을 외부 데이터(JSON)로 변환에 필요한 프로토콜)
"Encodable(엔코더블)"을 준수하는 객체는 객체의 프로퍼티를 외부 데이터 형식(JSON)으로 인코딩 가능해야 함
CodingKeys(코디키즈)는 인코딩 할 때, 프로퍼티들에 대한 매핑을 제공하는 역할 (아래 예시참고)
// id라는 프로퍼티의 인코딩 키를 key로, name 프로퍼티의 인코딩 키를 프로퍼티 이름과 동일하게 지정한 예시
struct User: Encodable {
let id: Int
let name: String
// 다른 프로퍼티들...
public enum CodingKeys: String, CodingKey {
case id = "key"
case name
}
// Encodable 프로토콜을 준수하기 위한 커스텀 인코딩 로직
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
// 다른 프로퍼티들도 인코딩 가능
}
}
4-3. Codable(코더블) 프로토콜
"Codable(코더블)" 프로토콜 → 두 가지 하위 프로토콜, "Encodable(엔코더블)"과 "Decodable(디코더블)" 을 결합한 것
public typealias Codable = Decodable & Encodable
외부 데이터(JSON)를 Swift의 데이터 모델로 변환,
Swift의 데이터 모델을 외부 데이터(JSON)로 변환을 모두 수행하여야 할 때,
Codable(코더블) 프로토콜을 사용 가능
CodingKeys(코딩키즈) 는 인코딩/디코딩 할 때,
프로퍼티들에 대한 매핑을 제공하는 역할
/*
id라는 프로퍼티의 인/디코딩 키를 key로, name 프로퍼티의 인/디코딩 키를
프로퍼티 이름과 동일하게 지정한 예시
*/
struct User: Codable {
let id: Int
let name: String
// 다른 프로퍼티들...
public enum CodingKeys: String, CodingKey {
case id = "key"
case name
}
// Encodable 프로토콜을 준수하기 위한 커스텀 인코딩 로직
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
// 다른 프로퍼티들도 인코딩 가능
}
// Decoding - 디코딩
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
}
}
4-4. JSON → Model 변환하기
위 내용을 바탕으로"Data Model" 작성 → | URL세션으로 받은 "Data" 타입을 "JSONDecoder(제이슨디코더)" 클래스를 사용 |
데이터를 모델 객체로 디코딩 |
do {
let user = try JSONDecoder().decode(User.self, from: data)
print("디코딩된 사용자: \(user)")
} catch {
print("디코딩 에러: \(error)")
}
위의 코드 "JSONDecoder().decode(_:from:)" 메서드를 사용 → JSON 데이터를 User 모델 객체로 디코딩
[ps. 만약 디코딩에 실패하면 catch 블록에서 에러 처리]
5. URLSession 을 통한 REST API 통신
아래 JSON Dummy API (제이슨 더미)를 활용 → 상품 정보 가져와 출력
API 정보
[GET] https://dummyjson.com/products/{ID}
ID의 범위: 1 ~ 100
Response JSON
{
"id": 1,
"title": "iPhone 9",
"description": "An apple mobile which is nothing like apple",
"price": 549,
"discountPercentage": 12.96,
"rating": 4.69,
"stock": 94,
"brand": "Apple",
"category": "smartphones",
"thumbnail": "https://i.dummyjson.com/data/products/1/thumbnail.jpg",
"images": [
"https://i.dummyjson.com/data/products/1/1.jpg",
"https://i.dummyjson.com/data/products/1/2.jpg",
"https://i.dummyjson.com/data/products/1/3.jpg",
"https://i.dummyjson.com/data/products/1/4.jpg",
"https://i.dummyjson.com/data/products/1/thumbnail.jpg"
]
}
// 예시코드
struct Product: Decodable {
let id: Int
let title: String
let description: String
let price: Double
let discountPercentage: Double
let rating: Double
let stock: Int
let brand: String
let category: String
let thumbnail: String
let images: [String]
}
let productID = 2
if let url = URL(string: "https://dummyjson.com/products/\(productID)") {
// URLSessionDataTask를 사용하여 비동기적으로 데이터 요청
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("Error: \(error)")
} else if let data = data {
do {
let product = try JSONDecoder().decode(Product.self, from: data)
print("Deocded Product: \(product)")
} catch {
print("Decode Error: \(error)")
}
}
}
// 네트워크 요청 시작
task.resume()
}
'IOS > Swift-Study' 카테고리의 다른 글
[Swift-Study] iOS 앱 개발 숙련 1주차 - 화면전환 (0) | 2024.04.14 |
---|---|
[Swift-Study] iOS 앱 개발 숙련 1주차 - 내부 저장소 (0) | 2024.04.12 |
[Swift-Study] iOS 앱 개발 숙련 1주차 - 메모리&ARC 개념 (0) | 2024.04.12 |
[Swift-Study] 베이직반 2회차 - 1회차 복습, Closure 활용 VC 간 통신 (0) | 2024.04.11 |
[Swift-Study] Swift 베이직반 1회차 - Xcode, 함수와 클로저, 변수와 상수 (0) | 2024.04.11 |