728x90
반응형
안녕하세요! 피피아노입니다 🎵
이번 포스팅에서는 실무에서 많이 쓰이는 기술인 RESTful API에 대해서 한번 공부해보려고 합니다.
그럼 바로 시작하겠습니다!
RESTful API란 무엇인가?
RESTful API는 Representational State Transfer (REST) 원칙에 따라 설계된 API를 의미합니다. REST는 웹 서비스 설계 아키텍처로, 클라이언트와 서버 간의 상호 작용을 단순화하고 표준화하는 데 중점을 둡니다. RESTful API는 HTTP를 사용하여 리소스(데이터)를 생성, 읽기, 업데이트 및 삭제(CRUD) 작업을 수행합니다.
RESTful API의 특징
- 무상태성(stateless): 각 요청은 클라이언트의 상태를 서버에 저장하지 않고 독립적으로 처리됩니다. 이는 서버 확장성을 높이고 클라이언트와 서버 간의 의존성을 줄입니다.
- 클라이언트-서버 구조: 클라이언트와 서버는 독립적으로 개발될 수 있으며, 클라이언트는 서버가 제공하는 API를 호출하여 필요한 데이터를 얻습니다.
- 캐시 가능성: RESTful 응답은 HTTP 캐시 메커니즘을 사용할 수 있어 성능을 향상시킵니다.
- 계층 구조: 클라이언트와 서버 사이에 미들웨어(예: 로드 밸런서, 프록시)가 있을 수 있으며, 이는 시스템의 확장성과 보안성을 높입니다.
- 통일된 인터페이스: 일관된 URI, HTTP 메서드, 상태 코드, 헤더 등을 사용하여 클라이언트가 서버와 상호작용할 수 있습니다.
왜 RESTful API를 사용하는가?
- 단순성과 명확성: REST는 HTTP 프로토콜을 기반으로 하여 잘 알려진 표준을 따릅니다. 이는 학습 곡선을 낮추고 이해하기 쉽게 만듭니다.
- 유연성: 다양한 클라이언트(웹, 모바일 앱 등)가 동일한 API를 사용할 수 있어 코드 재사용성을 높입니다.
- 확장성: 무상태성 덕분에 서버를 쉽게 확장할 수 있습니다.
- 성능: 캐시를 사용함으로써 네트워크 성능을 최적화할 수 있습니다.
REST와 SOAP 비교
SOAP(Simple Object Access Protocol)은 REST와 다른 웹 서비스 프로토콜입니다. SOAP는 XML 메시지를 사용하고 복잡한 보안 및 거래 메커니즘을 포함하고 있지만, REST는 더 가볍고 HTTP 표준을 따릅니다. REST는 단순함과 확장성 때문에 더 널리 사용됩니다.
RESTful API 사용 방법
기본적인 HTTP 메서드
- GET: 서버로부터 리소스를 조회
- POST: 서버에 새로운 리소스를 생성
- PUT: 서버의 리소스를 업데이트
- DELETE: 서버의 리소스를 삭제
- PATCH: 서버의 리소스를 부분적으로 변경할 때 사용
iOS에서 RESTful API 사용하기
1. URLSession을 이용한 RESTful API 호출
iOS에서 RESTful API를 호출하는 가장 일반적인 방법은 URLSession을 사용하는 것입니다.
import Foundation
struct Post: Codable {
let id: Int
let title: String
let body: String
}
class APIClient {
let baseURL = URL(string: "https://jsonplaceholder.typicode.com")!
func fetchPosts(completion: @escaping ([Post]?) -> Void) {
// 요청할 URL 설정
let url = baseURL.appendingPathComponent("posts")
// URLSession 데이터 태스크 생성
let task = URLSession.shared.dataTask(with: url) { data, response, error in
// 에러 처리
guard let data = data, error == nil else {
print("Error fetching data: \(String(describing: error))")
completion(nil)
return
}
// JSON 디코딩
do {
let posts = try JSONDecoder().decode([Post].self, from: data)
completion(posts)
} catch {
print("Error decoding JSON: \(error)")
completion(nil)
}
}
// 태스크 시작
task.resume()
}
}
let apiClient = APIClient()
apiClient.fetchPosts { posts in
if let posts = posts {
for post in posts {
print("Post \(post.id): \(post.title)")
}
}
}
- URLSession.shared.dataTask: URLSession의 공유 인스턴스를 사용하여 데이터 태스크를 생성합니다. 여기서 with 파라미터로 URL을 전달하여 서버에 요청을 보냅니다.
- data, response, error: 클로저에서 요청의 결과로 반환되는 데이터, 응답, 오류를 처리합니다.
- JSONDecoder: 응답 데이터를 [Post] 타입으로 디코딩합니다. Post는 Codable 프로토콜을 준수해야 합니다.
2. Alamofire를 이용한 RESTful API 호출
Alamofire는 Swift 기반의 HTTP 네트워킹 라이브러리로, URLSession보다 간단하게 네트워크 요청을 처리할 수 있습니다.
import Alamofire
struct Post: Codable {
let id: Int
let title: String
let body: String
}
class APIClient {
let baseURL = "https://jsonplaceholder.typicode.com"
func fetchPosts(completion: @escaping ([Post]?) -> Void) {
// Alamofire를 사용하여 요청
AF.request("\(baseURL)/posts").responseData { response in
switch response.result {
case .success(let data):
// JSON 디코딩
do {
let posts = try JSONDecoder().decode([Post].self, from: data)
completion(posts)
} catch {
print("Error decoding JSON: \(error)")
completion(nil)
}
case .failure(let error):
// 에러 처리
print("Error fetching data: \(error)")
completion(nil)
}
}
}
}
let apiClient = APIClient()
apiClient.fetchPosts { posts in
if let posts = posts {
for post in posts {
print("Post \(post.id): \(post.title)")
}
}
}
- AF.request: Alamofire의 기본 요청 메서드로, URL 문자열을 전달하여 요청을 만듭니다.
- responseData: 응답 데이터를 Data 타입으로 처리합니다.
- response.result: 결과를 성공과 실패로 나누어 처리합니다.
- success(let data): 요청이 성공하면 데이터를 JSON으로 디코딩합니다.
- failure(let error): 요청이 실패하면 오류를 처리합니다.
3. Combine을 이용한 RESTful API 호출
Combine 프레임워크를 사용하여 비동기 네트워크 요청을 더욱 선언적으로 처리할 수 있습니다.
import Combine
import Foundation
struct Post: Codable {
let id: Int
let title: String
let body: String
}
class APIClient {
let baseURL = URL(string: "https://jsonplaceholder.typicode.com")!
var cancellables = Set<AnyCancellable>()
func fetchPosts() -> AnyPublisher<[Post], Error> {
// URL 설정
let url = baseURL.appendingPathComponent("posts")
// Combine을 사용하여 네트워크 요청
return URLSession.shared.dataTaskPublisher(for: url)
.map { $0.data } // 응답 데이터 추출
.decode(type: [Post].self, decoder: JSONDecoder()) // JSON 디코딩
.eraseToAnyPublisher() // 타입 변환
}
}
let apiClient = APIClient()
apiClient.fetchPosts()
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Finished")
case .failure(let error):
print("Error: \(error)")
}
}, receiveValue: { posts in
for post in posts {
print("Post \(post.id): \(post.title)")
}
})
.store(in: &apiClient.cancellables)
- URLSession.shared.dataTaskPublisher: URLSession의 데이터를 Combine 퍼블리셔로 처리합니다.
- map { $0.data }: 응답 데이터만 추출합니다.
- decode(type:decoder:): JSON 데이터를 [Post] 타입으로 디코딩합니다.
- eraseToAnyPublisher: 퍼블리셔의 타입을 AnyPublisher로 변환하여 반환합니다.
- sink(receiveCompletion:receiveValue:): 퍼블리셔에서 데이터를 구독하고 처리합니다.
- store(in:): 구독을 취소할 수 있도록 cancellables에 저장합니다.
오늘은 여기까지 :)
감사합니다.
잘못된 내용이 있거나 더 좋은 내용 피드백은 언제나 환영합니다!
궁금하신 부분은 댓글로 질문 부탁드립니다!
728x90
반응형
'Apple > iOS' 카테고리의 다른 글
[iOS] CocoaPods 알아보기 (5) | 2024.08.13 |
---|---|
[iOS] Live Activity 알아보기 (0) | 2024.08.09 |
[iOS] Core Data는 뭘까? (0) | 2024.05.24 |
[iOS] Open API 연결하는 방법 (0) | 2024.05.19 |
[iOS] 화면 전환 방식 (Present, NavigationController + Source, NavigationController + Segue) (0) | 2024.03.24 |