Development/ETC

RESTful API 디자인의 핵심: Best Practices

Danny Seo 2024. 2. 15. 22:56

목차

    RESTful API

    RESTful 은 현재 웹 데이터 인터페이스 설계에 있어 가장 선호되는 API 디자인으로 널리 채택되고 있습니다.

    이러한 API를 디자인하는 기본 원칙들은 직관적으로 이해할 수 있지만, 세부적인 요소들을 정확히 구현하는 데는 주의와 노력이 필요합니다.

    이 글은 RESTful의 디자인 세부 정보를 요약해 보고 이해하고 사용하기 쉬운 API를 디자인하는 방법을 소개하겠습니다.

     

    1. URL 디자인

    1.1 동사 + 목적어

    RESTful의 핵심 아이디어는 클라이언트가 보낸 데이터 작업 지시사항이 "동사 + 목적어" 구조에 있어야 한다는 것입니다.

    예를 들어, 명령어 GET /articles에서 GET은 동사이고 /articles는 목적어입니다.

    동사는 일반적으로 CRUD 작업을 나타내는 다섯 가지 HTTP 메소드와 일치합니다:

    • GET: 읽기
    • POST: 생성
    • PUT: 업데이트
    • PATCH: 업데이트, 일반적으로 부분적인 업데이트입니다.
    • DELETE: 삭제

    HTTP 사양에 따르면 동사는 항상 대문자입니다.


    1.2 동사의 범위

    일부 클라이언트는 GETPOST 메소드만 사용할 수 있습니다. 서버는 다른 세 가지 메서드(PUT, PATCH, DELETE)를 모방하기 위해 POST를 수락(Accept) 해야 합니다.


    이 경우 클라이언트의 HTTP 요청은 X-HTTP-Method-Override 속성을 포함하여 서버에게 어떤 동사를 사용할지 알리고 POST 메서드를 대체해야 합니다.


    예시:

    POST /api/Person/4 HTTP/1.1  
    X-HTTP-Method-Override: PUT


    1.3 목적어는 명사여야 합니다

    목적어는 API의 URL로, HTTP 동사의 대상입니다. 목적어는 동사가 아닌 명사를 사용해야 합니다.
    예를 들어, /articles은 올바른 URL이지만, 아래 URL들은 명사가 아니기 때문에 올바르지 않습니다:

    • /getAllCars
    • /createNewCar
    • /deleteAllRedCars


    1.4 복수형 URL

    URL은 명사이므로 복수형 또는 단수형중 어느 것을 선택해야 할까요?

    이에 대한 통일된 규칙은 없지만, 일반적인 실천 방법은 모음을 읽는 것입니다.
    예를 들어 GET /articles(모든 기사 읽기)와 같이 복수형으로 사용해야 합니다.

    일관성을 위해 복수형 URL을 사용하는 것이 좋습니다.
    예를 들어 GET /articles/2가 GET /article/2보다 나은 방법입니다.


    1.5 다단계 URL 피하기

    일반적인 상황에서 리소스를 여러 수준으로 분류해야 될 때가 있습니다.
    예를 들어, 아래와 같이 특정 작가의 카테고리에 도달하기 쉽게 아래와 같이 '다단계' URL을 생성할 수 있습니다.

    예시:

    GET /authors/12/categories/2

    하지만, 이러한 유형의 URL은 확장 가능성을 증진시키지 않으며 의미도 불명확합니다.
    종종 의미를 이해하는 데 시간이 걸립니다.


    더 나은 접근 방식은 첫 번째 수준을 제외한 모든 수준에 대해 쿼리 문자를 사용하는 것입니다.

    GET /authors/12?categories=2

    또 다른 예는 발행된 기사를 쿼리 하는 것입니다.

    GET /articles/published

    쿼리 문자의 쓰기 스타일이 더 나은 것입니다.

    GET /articles?published=true

     

    2. 상태 코드

    2.1 상태 코드는 정확해야 합니다

    클라이언트의 모든 요청에 대해 서버는 응답해야 합니다. 응답에는 HTTP 상태 코드와 데이터가 포함됩니다.

    HTTP 상태 코드는 다섯 가지 범주로 나뉘는 세 자리 숫자입니다:

    • 1xx: 관련 정보
    • 2xx: 작업 성공
    • 3xx: 리디렉션
    • 4xx: 클라이언트 오류
    • 5xx: 서버 오류

    이 다섯 가지 범주에는 총 100가지가 넘는 상태 코드가 포함되어 있으며 대부분의 가능한 상황을 다룹니다.
    각 상태 코드에는 표준(또는 합의된) 설명이 있으며 클라이언트는 상태 코드를 확인함으로써 일어난 일을 간단히 파악할 수 있습니다.
    따라서, 서버는 가능한 정확한 상태 코드를 반환해야 합니다.


    API는 1xx 상태 코드를 필요로 하지 않습니다.
    다른 네 가지 범주의 상태 코드의 정확한 의미는 아래에서 설명합니다.

     

    2.2 2xx 상태 코드

    200 상태 코드는 작업이 성공적으로 완료되었음을 나타냅니다.
    몇몇의 메서드에서는 더 정확한 상태 코드를 반환할 수 있습니다.

    예시:

    • GET: 200 OK
    • POST: 201 Created
    • PUT: 200 OK
    • PATCH: 200 OK
    • DELETE: 204 No Content

     

    2.3 3xx 상태 코드

    API는 301 상태 코드(영구 리디렉션)와 302 상태 코드(임시 리디렉션, 또는 307로도 알려짐)를 사용할 필요가 없습니다.
    왜냐하면 이러한 상태 코드는 애플리케이션 수준에서 반환될 수 있으며 브라우저가 직접 이동합니다.
    API 수준에서는 이러한 두 상황을 고려할 필요가 없습니다.

    API에서 사용되는 3xx 상태 코드는 주로 다음과 같습니다:

    • 303 See Other: 다른 URL을 참조함을 의미합니다.
      이는 "임시 리디렉션"을 의미하는 302와 307과 동일한 의미를 가지지만, 302 및 307은 GET 요청에 사용되며 303은 POST, PUT 및 DELETE 요청에 사용됩니다.
      303 상태 코드를 수신한 후 브라우저는 자동으로 리디렉션 하지 않고 사용자에게 다음에 무엇을 할지 결정하도록 합니다.

    예시:

    HTTP/1.1 303 See Other
    Location: /api/orders/12345

     

    2.4 4xx 상태 코드

    4xx 상태 코드는 클라이언트 오류를 나타내며 주로 다음과 같은 유형이 있습니다:

    • 400 Bad Request: 서버가 클라이언트의 요청을 이해하지 못하고 아무 조치도 취하지 않습니다.
    • 401 Unauthorized: 사용자가 인증 자격 증명을 제공하지 않았거나 인증을 통과하지 못했습니다.
    • 403 Forbidden: 사용자가 식별 확인을 통과했지만 리소스에 액세스 할 권한이 없습니다.
    • 404 Not Found: 요청한 리소스가 존재하지 않거나 사용할 수 없습니다.
    • 405 Method Not Allowed: 사용자가 인증을 통과했지만 사용된 HTTP 메서드는 권한 내에 있지 않습니다.
    • 410 Gone: 요청한 리소스가 이 주소에서 이동되었으며 더 이상 사용할 수 없습니다.
    • 415 Unsupported Media Type: 요청된 반환 형식이 지원되지 않습니다. 예를 들어, API는 JSON 형식만 반환할 수 있지만 클라이언트가 반환되는 XML 형식을 요청했습니다.
    • 422 Unprocessable Entity: 클라이언트가 업로드한 첨부 파일을 처리할 수 없어 요청이 실패했습니다.
    • 429 Too Many Requests: 클라이언트 요청 수가 제한을 초과했습니다.

     

    2.5 5xx 상태 코드

    5xx 상태 코드는 서버 오류를 나타냅니다. 일반적으로 API는 사용자에게 서버에 대한 자세한 정보를 공개하지 않으므로 두 가지 상태 코드만 충분합니다:

    • 500 Internal Server Error: 클라이언트의 요청은 유효하지만 서버 처리 중 예기치 않은 오류가 발생했습니다.
    • 503 Service Unavailable: 서버가 요청을 처리할 수 없으며 일반적으로 웹 사이트 유지보수 상태에 사용됩니다.

     

    3. 서버 응답

    3.1 Plain Text를 반환하지 마세요

    API가 반환하는 데이터 형식은 일반 텍스트가 아닌 JSON 객체여야 하므로 표준화된 구조화된 데이터를 반환할 수 있습니다.
    따라서, 서버 응답의 HTTP 헤더의 Content-Type 속성은 application/json으로 설정해야 합니다.

    클라이언트 측에서 요청할 때도 JSON 형식이 허용된다고 명시적으로 서버에 알려야 합니다. 즉, 요청의 HTTP 헤더의 ACCEPT 속성도 application/json으로 설정해야 합니다.

    예시:

    GET /orders/2 HTTP/1.1 
    Accept: application/json

     

    3.2 오류 발생 시 200 상태 코드를 반환하지 마세요

    잘못된 방법 중 하나는 오류가 발생해도 200 상태 코드를 반환하고 오류 메시지를 데이터 본문에 넣는 것입니다.

    예시:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "status": "failure",
      "data": {
        "error": "Expected at least two items in list."
      }
    }

    위의 코드에서 데이터 본문을 파싱 한 후에야 작업이 실패했음을 알 수 있습니다.

    올바른 접근 방식은 상태 코드가 발생한 오류를 반영하고 특정 오류 정보가 데이터 본문 내에 반환되도록 하는 것입니다.

    예시:

    HTTP/1.1 400 Bad Request
    Content-Type: application/json
    
    {
      "error": "Invalid payoad.",
      "detail": {
         "surname": "This field is required."
      }
    }

     

    3.3 링크 제공

    API 사용자는 URL이 어떻게 디자인되었는지를 반드시 알 필요는 없습니다.
    하나의 해결책은 응답에 관련 링크를 제공하여 추가 작업을 용이하게 하는 것입니다.
    이렇게 하면 사용자는 다른 URL을 발견하기 위해 하나의 URL만 기억하면 됩니다.
    해당 방법을 HATEOAS라고 합니다.

     

    예시:

    {
      ...
      "feeds_url": "https://api.github.com/feeds",
      "followers_url": "https://api.github.com/user/followers",
      "following_url": "https://api.github.com/user/following{/target}",
      "gists_url": "https://api.github.com/gists{/gist_id}",
      "hub_url": "https://api.github.com/hub",
      ...
    }

    위의 응답에서 선택한 URL에 액세스 하여 다른 URL을 얻을 수 있습니다.
    사용자에게는 URL 디자인을 기억할 필요가 없으며 api.github.com에서 단계별로 검색하기만 하면 됩니다.

     

    HATEOAS의 형식에 대한 통일된 명세는 없습니다.
    위의 예에서 GitHub은 다른 속성과 함께 관련 링크를 함께 두었습니다.
    더 좋은 실천 방법은 관련된 링크를 다른 속성에서 분리하는 것입니다.

     

    예시:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "status": "In progress",
       "links": {[
        { "rel":"cancel", "method": "delete", "href":"/api/status/12345" } ,
        { "rel":"edit", "method": "put", "href":"/api/status/12345" }
      ]}
    }

     

    4. 참고 링크

    지금까지 RESTful API 디자인에 대해 알아보았습니다.
    조금이나마 도움이 되셨으면 좋겠습니다.
    감사합니다 :) 


    읽어주셔서 감사합니다! 😊
    개발 관련 궁금증이나 고민이 있으신가요?
    아래 링크를 통해 저에게 바로 문의해 주세요! 쉽고 빠르게 도움 드리겠습니다.

    '개발자서동우' 프로필 사진