REST API
- REST(Representational State Transfer)
- API의 엔드포인트 구조를 구현하는 방식
- 자원(resource) : URI로 표현
- HTTP method(POST, GET, PUT, DELETE) 사용
- 리소스에 행하는 행위를 표현

주요 메소드
GET : 리소스 조회
POST: 요청 데이터 처리, 주로 등록에 사용
PUT : 리소스를 대체(덮어쓰기), 해당 리소스가 없으면 생성
PATCH : 리소스 부분 변경 (PUT이 전체 변경, PATCH는 일부 변경)
DELETE : 리소스 삭제
기타 메소드
HEAD : GET과 동일하지만 메시지 부분(body 부분)을 제외하고, 상태 줄과 헤더만 반환
OPTIONS : 대상 리소스에 대한 통신 가능 옵션(메서드)을 설명(주로 CORS에서 사용)
CONNECT : 대상 자원으로 식별되는 서버에 대한 터널을 설정
TRACE : 대상 리소스에 대한 경로를 따라 메시지 루프백 테스트를 수행
GET
- 전체 리스트 조회 : GET/resoures
- 특정 리소스 조회 : GET/resources/:id

POST
- 새로운 자원 생성
- 서버에 Data 전송하기 위함(생성)
- PUT - 서버의 Resource에 대한 Data를 저장
- 생성 : POST/resources
body : {data : "data"}
Content-Type : "application/json"
PATCH
- 존재하는 자원에 대한 부분 변경
- 특정 리소스 수정 : PATCH/resources/:id

PUT
- 존재하는 자원 변경
- 리소스 수정 : PUT/resources/:id
body : {data : "data"}
Content-Type : "application/json"
DELETE
- 존재하는 자원에 대한 삭제
- 특정 리소스 삭제 : DELETE/resources/:id
디자인 가이드
- URI는 정보의 자원을 표현
- 리소스 명은 동사보다 명사 사용
- 자원에 대한 행위는 HTTP Method로 표현
GET /members/1 // OK
GET /membeers/retrive/1 // not OK
| 요청 | URL 예제 |
|---|---|
| 아메리카노 한 잔 주세요 | /coffee/americano |
| 망고 프라푸치노 한 잔 주세요 | /frappuccino/mango |
| 콜드브루 두 잔 주세요 | /coffee/coldbrew?quantity=2 |
| 아메리카노 두 잔 전부 헤이즐넛 시럽 넣어주세요 | /coffee/americano?quantity=2&syrup=hazelnet |

HTTP 상태코드


Retrofit
- Square사 제작
- HTTP 클라이언트 라이브러리
- 안드로이드, Kotlin(JAVA)에서 HTTP API 통신을 위한 타입 안전성(type-sate)을 지원
- 서버 - 클라이언트 데이터 교환 단순화, JSON 형식 이용
- JSON → 객체 변환(Gson, Moshi 등)
- 비동기 네트워크 처리 간편화(자체적 비동기 처리 지원)
특징
- 유형 안전성(Type-safe) : 데이터 형식 지정 → 컴파일 오류 감지
- 간결한 코드 작성 : interface, annotation → API 요청 정의, 자동 파싱 기능
- 확장성 : 다양한 COnverter(예 Gson, Moshi)를 지원
- JSON, XML 등 데이터 포맷 처리
- RxJava, Coroutines와 같은 비동기 프로그래밍 라이브러리와 연동 가능
- 비동기 처리
- OkHttp 기반 : OkHttp 라이브러리를 기반으로 구축 → 안정성과 성능 보장
사용 방법
- build.gradle 의존성 추가
// build.gradle (Module: app)
dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.x.x'
implementation 'com.squareup.retrofit2:converter-gson:2.x.x' // Gson 컨버터 추가
}
- AndroidManifest.xml 권한 추가
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
...
<application
...
- interface 생성
// 서버 응답으로 받아올 데이터 모델 클래스
interface ApiService {
@GET("users/{id}")
fun getUser(@Path("id") id: Int): Call<User>
}
- Retrofit 인스턴스를 생성
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
- 동기식 요청
al response: Response<User> = apiService.getUser(id).execute()
- 비동기식 요청
apiService.getUser(id).enqueue(object: Callback<User> {
override fun onResponse(call: Call<User>, response: Response<User>) {
if (response.isSuccessful) {
val user: User? = response.body()
}
}
override fun onFailure(call: Call<User>, t: Throwable) {
// 오류 처리
Log.e("API_ERROR", t.message ?: "Unknown error")
}
})
핵심 개념
- annotation
- HTTP 메소드 :
@GET,@PUT,@DELETE,@PATCH - API 요청 파라미터 지정 :
@Path,@Query,@Body
- HTTP 메소드 :
- Call : 비동기 API 요청을 나타내는 인터페이스
- Callback : API 응답을 처리하는 인터페이스
- Converter : JSON, XML 등 데이터를 객체러 변환해주는 라이브러리
public interface ApiService {
//POST 요청: 새 사용자 생성
@POST("users")
suspend fun createUser(@Body user: User)
// PUT 요청: 사용자 정보 업데이트
@PUT("users/{id}")
suspend fun updateUser(@Path("id") userId: Int, @Body user: User)
// DELETE 요청 : 사용자 삭제
@DELETE("users/{id}")
suspend fun deleteUser(@Path("id") userId: Int)
}
쿼리, 경로 파라미터
@Path: 경로파라미터, URL 경로의 일부로 사용되는 변수- 주로 정제되지 않은 데이터(조건 X)
@Query: 쿼리 파라미터, URL 쿼리 문자열로 전달되는 변수- 조건을 통한 데이터 선택(SELECT)



요청(Request Body)
@Body: POST, PUT 요청에서 JSON 데이터를 전송하기 위한 본문- 요청/응답의 실제 데이터(payload)
- 일반적으로 JSON, XML, Form 데이터 등
@Body→ 객체를 JSON으로 직렬화해서 요청 본문에 넣음@Field,@FormUrlEncoded→ 폼 데이터 전송@Part,@Multipart→ 파일 업로드
public interface ApiService {
//POST 요청: 새 사용자 생성
@POST("users")
suspend fun createUser(@Body user: User)
// 쿼리 파라미터 사용
@GET("users")
suspnd fun getUserByAge(@Query("age") age: Int): User
}
data class UserUpdateRequest(
val name: String,
val email: String
)
interface ApiService {
@PUT("users/{id}")
suspend fun updateUser(
@Path("id") userId: Int,
@Body request: UserUpdateRequest // body에 JSON 담김
): Response<User>
}
헤더(Headers)
@Headers: API 요청 시 특정 헤더- 요청/응답에 대한 부가 정보(metadata)
- 요청 자체를 설명하거나 인증/인코딩/캐시 등 프로토콜 수준의 정보를 담음
{}: 복수 헤더 설정
public interface ApiService {
// 단일 헤더 설정
@GET("users")
suspend fun getUsers(@Headers("Authorization") token: String): List<User>
// 복수 헤더 설정
@Headers({ "Accept: application/json", "User-Agent: Retrofit-Sample" })
@GET("users")
suspend fun getUsersWithHeaders()
}
interface ApiService {
@GET("users")
suspend fun getUsers(
@Header("Authorization") token: String, // 동적 헤더
@Header("Accept") accept: String = "application/json" // 기본값
): Response<List<User>>
}
clean architecture
- UI Layer : 데이터 표시 및 사용자 입력 처리 (Jetpack Compose)
- ViewModel : UI와 데이터 계층 연결, LifecycleScope 내에서 비동기 실행
- Repository: API 호출 로직을 한 곳에 모아 UI에서 직접 네트워크 호출하지 않도록 함
- Retrofit : API 호출 및 JSON → 객체 변환 담당
- REST API 서버 : 외부 데이터 제공
예시
- https://velog.io/@haileeyu21/Session-RESTful-API-%EB%9E%80-Path-parameters-Query-string
- 주목해야할 점은 RESTful API 관점에서의 주소 이름이다.
- 장바구니에서
수량 삭제와 추가(PATCH),아이템 삭제(DELETE),장바구니 데이터 받아오기(GET)모두 같은 API URI에서 이루어진다는 점이다.즉, 장바구니 데이터가 중심이 되어order/cart라는 URI에method에 따라 행할 수 있는 행위를 정하는 것이다.
addItem = e => {
fetch("http://10.168.1.160:8000/order/cart", {
method: "PATCH",
body: JSON.stringify({
cart_item_id: e.target.id,
delta: "plus",
}),
})
.then(res => res.json())
.then(result => {
result.MESSAGE === "SUCCESS" ? this.getData() : console.log("실패!");
});
};
{/*이외에도 수량 감소, 삭제(DELETE) 등에 대한 함수가 있다.*/}
getData = async () => {
const response = await fetch("http://10.168.1.160:8000/order/cart");
const data = await response.json();
this.setState({ cartData: data.items_in_cart });
};
C
Contents
