오늘 소개할 것은 대충 어떻게 사용하는지만 보고 확실한 개념을 잡지 않았던 REST API에 대해서 알아볼 것이다.
용어 정의
클라이언트
웹에서 정보에 액세스하려는 모든 것을 사용자라고 한다. 클라이언트는 API를 사용하는 사람이 될 수도 있고 소프트웨어 시스템일 수도 있다.
리소스와 서버
리소스는 API를 통해 클라이언트에게 제공하는 정보이다. 리소스는 이미지, 동영상, 텍스트, 숫자 또는 모든 유형의 데이터일 수도 있습니다. 또한 클라이언트에 리소스를 제공하는 시스템을 서버를 말한다.
API
애플리케이션 프로그래밍 인터페이스(API)는 다른 소프트웨어 시스템과 통신하기 위해 따라야하는 규칙을 말한다. 개발자는 다른 애플리케이션이 프로그래밍 방식으로 애플리케이션과 통신할 수 있도록 API를 표시하거나 생성한다.
쉽게 말해, 클라이언트는 개발자가 만든 통신 규칙에 따라 리소스를 요청하고 그에 맞는 응답을 제공한다.
RESTful API 또는 REST API란?
API 작동 방식에 대한 조건을 부과하는 소프트웨어 아키텍쳐를 말한다. API를 만들게 되면 개발자에 따라 응답, 요청하는 방식, 엔드포인트의 스타일 등 많고 복잡한 스타일을 가질 수 있다. 이렇게 복잡한 API를 통일하고자 REST 아키텍처 스타일을 따르는 API를 말한다. RESTful API라는 용어는 일반적으로 RESTful 웹 API를 나타내지만, REST API라는 용어와 같은 의미로 사용할 수 있다.
아키텍쳐란?
전체적인 시스템을 나타내는 전체 구조 또는 설계를 말한다.
REST API 구성 요소
고유 리소스 식별자
서버는 고유한 리소스 식별자로 각 리소스를 식별한다. REST 서비스의 경우 서버는 URL을 통해 각 리소스 식별을 수행하는데 쉽게 말해, 각 API는 고유한 URL을 가지고 사용자는 해당 URL을 통해 리소스에 접근, 수정 등을 요청할 수 있다.
메소드
메소드는 리소스에 수행해야하는 작업을 서버에 알려주는 역할을 하며, 일반적으로는 4가지가 있다. 이것은 밑에서 좀 더 자세히 다뤄보자.
HTTP 헤더
요청 헤더는 클라이언트와 서버 간에 교환되는 메타데이터이다. 예를 들어, 요청 헤더는 응답 및 요청의 형식을 나타내고 요청 상태 등에 대한 정보를 제공한다.
메타데이터란?
데이터를 설명하기 위한 데이터로써, 데이터에 대한 정보를 뜻합니다.
데이터
REST API 요청에는 POST, PUT 및 기타 HTTP 메소드가 작동하기 위해서는 필요로 하는 데이터가 존재한다.
REST API 메소드
메소드의 대표적인 5가지만 알아보겠습니다.
GET
서버의 지정된 URL에 있는 리소스에 액세스하는 메소드로써, GET 요청을 캐싱하고 RESTful API 요청에 파라미터를 넣어 전송하여 전송 전에 데이터를 필터링하도록 서버에 요청할 수 있다.
즉, 한 개 또는 여러 개의 리소스를 가져올 때 사용합니다.
Path Parameter
대부분 리소스의 특정한 부분을 지칭할 때 사용한다.
GET /user/1 => user_id가 1인 상태
GET /user/123 => user_id가 123인 상태
Query String
필터링, 정렬, 검색, 페이지네이션 등에 사용된다.
Query Strng의 시작은 ?로 나타내며 각 파라미터=값으로 이루어져있다. 여러 개의 파라미터를 사용하고싶으면 &를 사용하여 이어붙이면 된다.
POST
요청과 함께 데이터를 넣어 리소스를 추가할 때 사용한다. 데이터에는 대표적으로 body와 formdata 등이 있다.
이 때, POST 요청은 캐싱이 되지 않기 때문에 여러 번 요청하면 리소스가 여러 번 생성한다.
Body와 Formdata란?
Body란 데이터를 전송할 때 사용하는 가장 기본적인 형태로 JSON, XML, 기타 형식 등으로 데이터를 보낼 수 있습니다.
Formdata란 말 그대로 폼 데이터를 전송할 때 사용하고, 텍스트 문자열로 구성됩니다. 파일 업로드에 매우 적합하므로, 파일을 다룰 때 많이 사용합니다.
PUT
서버의 기존 리소스의 모든 정보를 업데이트 할 때 사용한다. 클라이언트는 업데이트가 되지 않은 데이터라도 모든 정보를 요청해야 하고, 제일 중요한 점은 멱등성을 가진다는 것이다.
멱등성이란?
연산을 여러 번 적용하여도 결과가 달라지지 않은 성질을 말하며, API에서는 동일한 호출이 여러 번 생겨도 결과 값이 같다라는 것을 뜻한다.
Patch
서버의 기존 리소스의 일부 정보를 업데이트할 때 사용합니다. PATCH와 다른 점은 일부 정보만 변경한다는 것이며, 멱등성이 적용되지 않기 때문에 POST 처럼 동일한 요청을 여러 번 하게 된다면 여러 번 리소스를 수정하게 됩니다.
Delete
서버의 기존 리소스를 삭제할 때 사용합니다. 말 그대로 리소스 삭제이기 때문에 딱히 설명할 것도 없다.
URL 구성은 어떻게 하면 좋을까?
이제 REST API의 정의와 기초에 대해서 모든 걸 배웠다. 그러면 REST API를 짜야하는데 이 "URL을 어떻게 짜면 좋을까?"라는 생각을 가지기 시작한다. 나 또한 그거 때문에 여러 가지를 찾아봤는데 거기서 대표적인 것을 소개하겠다.
단수말고 복수형
API 엔드 포인트를 작성할 때 가장 먼저 고민하는 것이라고도 생각한다. 현재까지도 관심이 많은 주제라고도 생각하지만 찾아볼 수록 복수를 사용하자는 쪽이 더 많기도 하다. 물론 단수형을 사용해도 상관은 없다라는 의견도 있지만 많이 사용하는 곳을 사용하는 게 좋기도 하고 합당한 이유가 많기도 하다.
단, 단수와 복수를 혼합하여 사용하지는 않습니다.
// 좋은 예
GET /users
GET /users/12
POST /users
// 나쁜 예
GET /user
동사말고 명사
어떠한 사용자를 가져오고싶다면 동사와 명사를 섞어 사용하시는 분들이 종종 있습니다. 하지만, 좋은 REST API를 사용하기 위해서는 동사를 지양해야 합니다. 또한 HTTP Method가 동사의 역할을 하기도 때문에 동사는 필요 없습니다.
// 좋은 예
GET /users => 유저 가져오기
GET /users/1 => 1번 유저 가져오기
POST /users => 유저 정보 추가
DELETE /users => 유저 삭제
// 나쁜 예
GET /getUsers
GET /getUsers/1
POST /addUsers
DELETE /deleteUsers
밑줄(_) 대신 하이픈(-)
URL이 길어지게 되면 하이픈을 사용하는 것이 좋습니다. 밑줄로 구분해도 URL에는 별 지장이 없지만 어떠한 곳에서 URL을 언급하거나 하이퍼링크를 걸 때 URL 밑에 밑줄이 그어지는 경우를 많이 보셨을 겁니다. 그렇게 되면 상황에 따라서는 밑줄이 아닌 공백으로 보일 수도 있는 혼동이 발생할 수 있습니다.
// 좋은 예
GET /products/long-example
// 나쁜 예
GET /products/long_example
대문자 보단 소문자
일반적으로 URL을 사용한다면 대부분 소문자를 사용합니다. URL에서는 대소문자를 구분하지는 않지만 리눅스 계열의 서버라면 대소문자를 구분하기 때문에 소문자로만 이루어지는 게 좋습니다.
리소스 관련 필터링은 Query String을 사용
리소스를 가져오게 된다면 필터링을 해야하는 경우가 정말 많습니다. 예를 들어 리소스에 대한 페이지네이션이라던지 특정 name을 가진 사람을 표시하고싶은 경우가 그 예입니다.
// 좋은 예
GET /users?name=chulsu
GET /users?name=chulsu&gender=male
// 나쁜 예
GET /users/chulsu
GET /users/chulsu/male
응답 코드(Status Code)
이제 마지막 챕터에 들어섰습니다! 마지막으로는 서버가 클라리언트에게 요청의 결과를 알려주는 응답 코드에 대해서 알아보겠습니다
200 OK
클라이언트가 요청한 사항을 성공적으로 처리 및 응답 값(response)이 있는 경우 사용합니다.
대부분 GET 요청이 성공했을 때 response와 함께 반환됩니다.
201 Created
클라이언트가 요청한 리소스를 성공적으로 추가한 경우 반환됩니다.
이 때, 반환 값은 없으며 응답 헤더에 Location이라는 값을 추가하여 새로운 정보를 확인할 수 있는 URL을 제공합니다.
204 No Content
클라이언트가 요청한 리소스를 성공적으로 처리 및 응답 값이 없는 경우 사용합니다.
400 Bad Request
요청 인자(request)가 없거나 부족 또는 양식에 맞지 않은 경우 사용합니다.
401 Unauthorized
해당 URL에 접근하기에 인증되지 않은 사용자 또는 인증이 부족한 사용자인 경우 사용합니다.
403 Forbidden
인증된 사용자가 적절하지 못한 권한으로 요청하는 경우 사용합니다.
예시로는 일반 사용자가 관리자 페이지에 접근하는 경우 사용할 수 있습니다.
404 Not Found
해당 URL이 존재하지 않는 경우 사용합니다.
여기서, 중요한 점은 Get 결과가 없으면 404를 사용하는 부분입니다.
유저의 정보를 get을 요청했다면 해당 user 컬렉션은 존재하지만 리소스는 존재하지 않은 것이므로, 404가 아닌 200과 빈배열을 반환해야 합니다.
만약 404를 반환하면 User의 정보를 찾을 수 없는 것인지, 해당 URL이 없다는 것인지 혼동을 줄 수 있기 때문입니다.
해당 이슈는 여기서 확인해볼 수 있습니다.
405 Method Not Allowed
클라이언트 요청이 허용되지 않은 메소드 또는 없는 메소드를 호출한 경우에 사용합니다.
409 Conflict
클라이언트 요청이 현재 서버의 리소스와 충돌되는 경우를 말합니다.
간단한 예로는 회원가입 시 이메일 중복, 닉네임 중복 시에 사용할 수 있습니다.
415 Unsupported Media Type
클라이언트 요청 시 서버가 지정한 Content-Type을 사용하지 않은 경우 사용합니다.
Content-Type이란?
보내는 데이터에 대한 형식을 명시하고 서버에게 알려주는 요청 헤더 중 하나입니다.
만약, body에서 JSON의 형식으로 데이터를 전송한다면 Content-Type은 application/json으로 사용할 수 있습니다.
Formdata 경우는 multipart/formdata를 사용합니다.
500 Internal Server Error
서버 내에서 발생하는 논리적 또는 물리적 오류로 인해 요청을 처리할 수 없는 경우에 사용합니다.
간단한 예로는 SQL 에러가 발생 또는 예기치 못한 오류가 발생하였을 때 사용할 수 있습니다.
'Project 하면서 알아가는 것들' 카테고리의 다른 글
[Nextjs] Tiptap 사용법과 커스텀마이징 기능 구현 (1) | 2024.02.28 |
---|---|
IoC, DI, DPI 확실히 개념 잡기 (0) | 2023.11.12 |
백엔드에서 이미지 업로드는 어떻게 하면 좋을까? (6) | 2023.11.01 |
typescript ?(Optional Parameters)와 | undefined(Union)의 차이 (0) | 2023.02.09 |
[JWT] Access Token과 Refresh Token 그리고 RTR 기법에 대해서 알아보자. (0) | 2023.01.15 |