iOS실무 9주차 Restful
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"isVerified": true,
"roles": ["user", "admin"],
"address": {
"city": "Seoul",
"zip": "12345"
}
}
다음부터는 open API를 활용한 실습을 진행하기때문에 영진위 api key 발급받기!
JSON형식으로 반횐되는것을 볼 수 있다.
{
"boxOfficeResult": {
"boxofficeType": "일별 박스오피스",
"showRange": "20250501~20250501",
"dailyBoxOfficeList": [
{
"rnum": "1",
"rank": "1",
"rankInten": "2",
"rankOldAndNew": "OLD",
"movieCd": "20232394",
"movieNm": "야당",
"openDt": "2025-04-16",
"salesAmt": "1329431600",
"salesShare": "25.2",
"salesInten": "691659920",
"salesChange": "108.4",
"salesAcc": "18667746190",
"audiCnt": "146883",
"audiInten": "65952",
"audiChange": "81.5",
"audiAcc": "1988683",
"scrnCnt": "1152",
"showCnt": "3442"
},
{
"rnum": "2",
"rank": "2",
"rankInten": "-1",
"rankOldAndNew": "OLD",
"movieCd": "20218800",
"movieNm": "거룩한 밤: 데몬 헌터스",
"openDt": "2025-04-30",
"salesAmt": "1144166180",
"salesShare": "21.7",
"salesInten": "211519880",
"salesChange": "22.7",
"salesAcc": "2116850480",
"audiCnt": "127361",
"audiInten": "10330",
"audiChange": "8.8",
"audiAcc": "248671",
"scrnCnt": "921",
"showCnt": "3404"
},
네이버의 통계를 확인해보면 영진위 api를 사용해 JSON데이터를 파싱하여 영화 순위를 보여주는 것을 알 수 있다.
https://codebeautify.org/jsonviewer
Best JSON Viewer and JSON Beautifier Online
Online JSON Viewer, JSON Beautifier and Formatter to beautify and tree view of JSON data - It works as JSON Pretty Print to pretty print JSON data.
codebeautify.org
JSON데이터를 예쁘게(보기쉽게) 볼 수 있는 사이트
Instantly parse JSON in any language | quicktype
app.quicktype.io
https://app.quicktype.io/
Instantly parse JSON in any language | quicktype
app.quicktype.io
위 사이트를 사용하면 JSON타입을 스위프트의 구조체, 클래스등으로 쉽게 만들 수 있다.
1. REST란?
REST(Representational State Transfer)는 웹의 아키텍처 스타일 중 하나로, 2000년대 초반에 로이 필딩(Roy Fielding)의 박사 논문에서 처음 제안되었습니다.
📌 REST의 핵심 개념
- 자원(Resource): URI로 표현됨. 예: /users/1, /posts
- 행위(Verb): HTTP 메서드로 표현. 예: GET, POST, PUT, DELETE
- 표현(Representation): JSON, XML 등으로 데이터 전송
행
RESTful API란 REST의 원리를 따르는 API를 의미합니다.
✅ RESTful API 설계의 6가지 핵심 원칙
1. 자원의 URI는 명사로 표현한다
- URI는 **데이터(자원)**를 식별하며, 행위는 HTTP 메서드로 표현한다.
- ❌ /getUser, /createPost → 비 RESTful
- ✅ /users, /posts/1 → RESTful
2. HTTP 메서드의 의미에 맞게 사용한다
GET | 자원 조회 (Read) |
POST | 자원 생성 (Create) |
PUT | 자원 전체 수정 (Update) |
PATCH | 자원 일부 수정 (Partial Update) |
DELETE | 자원 삭제 (Delete) |
3. 계층적 URI 구조를 따른다
- 자원 간 관계는 계층 구조로 표현한다.
4. 무상태성 (Stateless)
- 서버는 요청 간 클라이언트 상태를 저장하지 않는다.
- 모든 요청은 자체적으로 완결적이어야 한다. 즉, 요청에 필요한 모든 정보(인증, 위치 등)를 포함해야 함.
5. 일관된 응답 구조와 상태 코드 사용
- 응답은 일반적으로 JSON 포맷을 사용하고, HTTP 상태 코드도 적절히 설정해야 한다.
200 | OK | 정상 처리됨 |
201 | Created | 자원 생성됨 (POST 요청 후) |
204 | No Content | 삭제 또는 응답 없음 |
400 | Bad Request | 요청 오류 |
401 | Unauthorized | 인증 실패 |
404 | Not Found | 자원 없음 |
500 | Internal Server Error | 서버 에러 |
6. HATEOAS (Hypermedia as the Engine of Application State) — 선택 사항
- 클라이언트가 서버의 응답에 포함된 링크 정보를 따라 추가 행동을 할 수 있게 하는 REST 원칙
- 실제 실무에서는 잘 사용되지 않거나 단순화된 형태로만 적용
✅ RESTful하지 않은 API 예시
→ 이런 API는 RESTful하지 않으며, 클라이언트-서버 간 역할 분리 및 확장성에 문제가 생길 수 있음
JSON이란?
JSON (JavaScript Object Notation)은 데이터를 구조화하여 저장하거나 네트워크를 통해 전송할 때 사용하는 텍스트 기반의 데이터 형식입니다.
- 가볍고, 사람이 읽기 쉬우며, 기계가 파싱하기 쉬움
- 대부분의 언어에서 쉽게 생성, 파싱, 변환 가능
- 특히 웹 API (특히 RESTful API)에서 표준 응답 형식으로 사용됨
JSON vs JavaScript 객체 리터럴
문자열 따옴표 | 항상 더블 쿼트 " " | 싱글 '도 허용 |
key 따옴표 | 항상 필요 | 생략 가능 |
주석 | ❌ 허용되지 않음 | ✅ 허용됨 (//, /* */) |
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"isVerified": true,
"roles": ["user", "admin"],
"address": {
"city": "Seoul",
"zip": "12345"
}
}
JSON 예시
API는 Application Programming Interface의 줄임말로 서로 다른 프로그램이나 컴포넌트 간에 기능이나 데이터를 주고받을 수 있도록 만든 명세 또는 규칙이다.
restful api
ex) GET /users/1 유저 1번 정보 요청 => 유저 1번 정보 name, age 등 응답
이를 공개적으로 누구나 접근할 수 있게 제공해주는것을 Open API라고 한다.
https://api.visitkorea.or.kr/#/
TourAPI4.0
누구나 쉽게 접근하고 활용 할 수 있는 다국어 관광정보 고객 맞춤형 데이터
api.visitkorea.or.kr
누구나 사용 가능한 관광 데이터
카카오와 같은 대기업에서 아래와 같이 오픈 API를 제공해주는 경우도 있다.
https://www.data.go.kr/data/15135102/openapi.do
한국관광공사의 반려동물 동반여부 api입니다.
반려 동물 동반여행지의 주변 좌표를 기반으로 관광정보 목록을 조회하는 기능입니다. 파라미터에 따라 제목순, 수정일순(최신순), 등록일순, 거리순 정렬검색을 제공합니다. |
struct Items: Codable {
let item: [Item]
}
struct Item: Codable {
let cpyrhtDivCd: String
let contentid: String
let contenttypeid: String
let title: String
let createdtime: String
let modifiedtime: String
let tel: String
let cat1: String
let cat2: String
let cat3: String
let addr1: String
let addr2: String
let areacode: String
let sigungucode: String
let mapx: String
let mapy: String
let mlevel: String
let dist: String
let firstimage: String
let firstimage2: String
}
다음과같이 1000m이내 반려동물 동반 관광지가 Json형태로 반환 => swift 구조체로 파싱하여 사용할 수 있다.
함수
함수를 잘 사용하기 위해서는 함수의 내부 매개변수와 외부 매개변수의 차이점
그리고 스위프트의 함수는 1급 객체이기 때문에 인자로 함수를 전달, 리턴받을 수 있다는 점 등을 잘 알아두어야 한다.
func add(x: Int, y: Int) -> Int {
return(x+y)
}
add(x:10, y:20) // 30
print(type(of:add)) // (Int, Int) -> Int
함수의 타입은 인자의 타입, 리턴형으로 자료형이 생성된다.
func add(first x: Int, second y: Int)
함수에서의 first를 argument label, x 를 parameter name이라고 한다.
func add(_ x: Int, with y: Int) -> Int {
print(#function) // add(_:with:)
return(x+y)
}
함수의 이름은 위와같이 나오는것을 알 수 있다.
스위프트의 함수는 다음 3가지를 만족하기 때문에 1급 객체(1급 시민) 이다
1) 변수에 저장할 수 있다.
2) 매개변수로 전달할 수 있다.
3) 리턴값으로 사용할 수 있다.
func up(num: Int) -> Int {
return num + 1
}
func down(num: Int) -> Int {
return num - 1
}
let toUp = up
print(up(num:10))
1) 변수에 저장할 수 있다.
func upDown(Fun: (Int) -> Int, value:Int) {
let result = Fun(value)
print(result)
}
func up (value: Int) -> Int {
return value + 10
}
upDown(Fun: up, value: 20)
2) 매개변수로 전달할 수 있다.
func createUp () -> (Int) -> Int {
func inner(value: Int) -> Int {
return value + 10
}
return inner
}
let up = createUp()
print(up(10))
3) 리턴값으로 사용할 수 있다.
클로저
클로저: 특정 작업(함수)과 그 작업이 일어난 곳(환경 또는 상태)을 모두 기억하고 있는 도구
let add1 = { (x: Int, y: Int) -> Int in
return(x+y)
}
print(add1(1,2))
print(type(of: add1)) // (Int, Int) -> Int
이를 클로저 표현식이라 하며,
익명함수에서는 아규먼트 레이블을 사용할 수 없다.
후행 클로저
func someFun(cl: () -> Void) {
cl()
}
// trailing closure를 사용 안하면
someFun(cl: {
print("후행 클로저 미사용")
})
// trailing closure 사용
someFun() { //"cl:"을 생략하고 함수 소괄호 다음에 클로저 작성
print("후행 클로저 사용 ")
}
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)
}
result = math(x: 1, y: 2, cal: {(a: Int, b: Int) -> Int in
return a + b
}) //클로저 소스를 매개변수에 직접 작성하면 코드가 더러워지며 가독성이 저하됨
result = math(x: 10, y: 20) {(a: Int, b: Int) -> Int in
return a + b
}//trailing closure를 더 많이 사용함
클로저 축약 표현
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)
}
//1. 리턴형 생략 (자동 타입 추론)
let result = math(x: 10, y: 20) {(a: Int, b: Int) in
return a + b
}
//2. 매개변수를 생략하고 단축인자 사용
let result2 = math(x: 10, y: 20) {
return $0 * $1
}
//클로저는 마지막줄을 리턴하므로 return 생략
let result3 = math(x: 20, y: 10) { $0 / $1 }
print(result)
print(result2)
print(result3)
디폴트 아규먼트
func sayHello(count: Int, name: String = "길동") {
print("\(name) 번호는 \(count)")
}
sayHello(count: 1, name:"하이") // 하이 번호는 1
sayHello(count: 2) // 길동 번호는 2
함수에 값이 들어오지 않았을때 기본으로 사용할 값을 지정 가능하다.
func present(
_ viewControllerToPresent: UIViewController,
animated flag: Bool,
completion: (() -> Void)? = nil
)
클로저와 디폴트 매개변수 활용 예시
completion 매개변수는 클로저를 사용하여 새로운 뷰 컨트롤러가 표시된 후의 동작을 정의할 수 있습니다. 이 매개변수는 디폴트 값으로 nil이 설정되어 있어, 필요하지 않을 경우 생략이 가능합니다.
예시 1: 기본 사용
present(alert, animated: true)
completion을 생략하여, 새로운 뷰 컨트롤러를 애니메이션과 함께 표시합니다.
예시 2: 클로저를 사용한 추가 동작 정의
present(alert, animated: true) { print("Alert가 화면에 표시되었습니다.") }
새로운 뷰 컨트롤러가 표시된 후, 콘솔에 메시지를 출력합니다.