Application Modernization/Others

REST API 설계 가이드

Cloud Applicaiton Architect 2021. 7. 11. 12:52
반응형

정의 및 특징

REST(REpresentational State Transfer) 자원(Resource)을 의미(Representation)로 구분하여 그 상태를 전달 하는 것을 뜻함

• 즉, HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고, HTTP Method(POST, GET, PUT, DELETE)를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것을 의미

 REST라는 단어는 Roy Fielding이 2000년 캘리포니아 대학교 어바인 캠퍼스의 박사논문으로 제출한 'Architectural Styles and the Design of Network-based Software Architectures'에서 처음으로 언급됨

REST는 표준이 정해져 있지 않지만 REST가 지양하는 아키텍처 요구사항을 모두 만족할 경우 이를 RESTful이라 함

 

Why REST?

 OpenAPI 의한 기업간 통신 표준(OAS: Open API Specification) 적용에 대한 대응 필요

 국제 표준 준수를 통해 관리를 위한 자동화, 표준화를 위한 기반 수립 필요

 어플리케이션간 분리, 통합을 위한 최신의 API 설계 기준 수립 필요

 시스템간 연계, 다양한 클라이언트 대응 필요

 

REST의 특징

특징 내용
유니폼인터페이스
(
Uniform)
URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일
무상태성
(
Stateless)
REST는 작업을 위한 상태정보를 따로 저장하고 관리하지 않음
세션 정보나 쿠키 정보를 별도로 저장하고 관리하지 않기 때문에 API서버는 들어오는 요청만을
단순 처리 가능

따라서, 서비스의 자유도가 높아지고 서버에서 불필요한 정보를 관리하지 않음으로써 구현이
단순해지는 장점 有
캐시가능
(
Cacheable)
HTTP프로토콜 표준에서 사용하는 LAST-Modified태그나 E-Tag를 이용해 캐싱 구현 가능
자체표현성
(
Self Descriptiveness)
REST API 메세지만 이용해 그 API를 이해 할 수 있는 자체 표현 구조로 구현
클라이언트/서버
(
Client/Server)
REST 서버는 API제공, 클라이언트는 사용자 인증이나 컨텍스트(세션,로그인 정보)등을 직접 관리
따라서, 클라언트/서버 각각의 역활이 확실히 구분되기 때문에 클라이언트와 서버에서 개발해야 내용이 명확해지고 서로간 의존성 감소
계층형구조
(
Hierachy)
REST 서버는 다중 계층으로 구성될 수 있으며, 보안로드 밸런싱, 암호화 계층을 추가해 구조상의 유연성을 둘 수있고 PROXY, 게이트웨이 같은 네트워크 기반의 중간매체를 사용할 수있게 함

 

REST3요소

구성 요소 내용 표현 방법
자원(Resource) 자원 HTTP URI /members/{1}, /member/
행위(Verb) 자원에 대한 행위 HTTP Method POST, GET, DELETE, PUT
표현(Representations) 자원에 대한 행위의 내용 (즉, 요청에 대한 Body) HTTP Message Payload (JSON, XML, TEXT, RSS 등) {  member-id:”82370”,  member-name:”홍길동“,  member-org:”10100”,  member-location:”11010” }

 

RESTful API Design Best Practices

1.  명사를 통한 리소스 식별

이해하기 쉽게 하기 위해 모든 리소스들에 대해 다음과 같은 구조를 적용

  • GET - /users - user 리스트를 반환
  • GET - users/100 - 조건 값을 주어진(100) 특정 사용자 반환
  • POST - /users - 신규 user 생성
  • PUT - /users/ - 사용자 업데이트
  • DELETE - /users/711 - 조건 값이 주어진(711) 사용자 삭제

다음과 같은 동사를 사용하지 말 것

  • /getAllUsers
  • /getUserById
  • /createNewUser
  • /updateUser
  • /deleteUser

 

2. HTTP헤더에 데이터 포맷 포함

클라이언트와 서버 모두 통신을 위해 어떤 포맷이 사용되었는지 알아야 할 필요가 있으며 따라서 이러한 포맷은 HTTP header에 명시되어야 한다.

  • Content-Type   Request 포맷을 명시
  • Accept               Acceptable한 response 포맷들의 리스트

 

3. GET이나 쿼리 파라미터를 통한 수정 금지

GET 메소드를 통해 값을 변경하지 말고 PUT, POST, DELETE등의 메소드들을 이용해 상태를 변경 해야한다. 즉, GET을 통해 CUD(Create, Update, Delete)를 수행하지 말라.

  • GET /users/711?activate or
  • GET /users/711/activate

4. 서브 URL 표현식을 통해 세부 표현

API내부에 다른 리소스와 관계가 있을때 서브 리소스 표현으로 그 관계를 표현한다.

METHOD API DESC.
GET  /cars/711/drivers/ 711번 id를 사용하는 car의 드라이버 리스트를 반환
GET  /cars/711/drivers/4 711번 id를 사용하는 car의 드라이버 중 드라이버 id가 4번인 드라이버를 반환
GET  /tickets/12/messages ticket 넘버 12번의 메시지 리스트 반환
GET  /tickets/12/messages/5 ticket 넘버 12번의 메시지 중 메시지 번호 5번 반환
POST  /tickets/12/messages ticket 넘버 12번에 새로운 메시지 생성
PUT  /tickets/12/messages  tcket 넘버 12번에 메시지 5번을 업데이트
PATCH  /tickets/12/messages/5 ticket 넘버 12번에 메시지 5번을 부분적으로 업데이트
DELETE  /tickets/12/messages/5 ticket 넘버 12번에 5번 메시지 삭제

 

5. 행위를 위한 적절한 HTTP 메소드(Verbs) 사용

METHOD DESC.
GET - 리소스 조회용
- URI 지정을 통해 리소스 정보 요청
- 응답 메시지의 본문에는 요청된 리소스의 세부 정보가 포함
POST - 신규 리소스 생성용
- 요청(Request) 메시지를 통해 신규 리소스 생성에 필요한 내용을 전달
- 단, POST는 실제 리소스 생성을 하지 않더라도 트리거링 하는 용도로도 사용될 수 있음
PUT - 기존 리소스 수정용
- 요청(Request) 메시지를 통해 리소스 수정에 필요한 내용을 전달
PATCH - 기존 리소스의 부분 변겅
- 요청(Request) 메시지를 통해 리소스 부분 수정에 필요한 내용을 전달
DELETE - 리소스 삭제용
- URL에 삭제할 리소스 전달을 통해 기존의 리소스 삭제

 

6. HTTP 응답 상태 코드 사용

클라이언트가 API를 통해 서버에 요청했을 때 클라이언트는 해당 요청에 대한 실패, 처리완료 또는 잘못된 요청등에 대한 피드백을 받아야 함. 이러한 응답 코드는 일련의 표준화된 코드 모음으로 제공되고 있음. RESTful을 통한 API 호출에 적절한 HTTP 응답 코드를 리턴 할 것

상태 코드 설명
200 클라이언트의 요청을 정상적으로 수행함
201 클라이언트가 어떠한 리소스 생성을 요청, 해당 리소스가 성공적으로 생성됨(POST를 통한 리소스 생성 작업 시)

 

상태 코드 설명
400 클라이언트의 요청이 부적절 할 경우 사용하는 응답 코드
401 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을 때 사용하는 응답 코드
(로그인 하지 않은 유저가 로그인 했을 때, 요청 가능한 리소스를 요청했을 때)
403 유저 인증상태와 관계 없이 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때 사용하는 응답 코드
(403 보다는 400이나 404를 사용할 것을 권고. 403 자체가 리소스가 존재한다는 뜻이기 때문에)

405
클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을 경우 사용하는 응답 코드

 

상태 코드 설명
301 클라이언트가 요청한 리소스에 대한 URI가 변경 되었을 때 사용하는 응답 코드
(응답 시 Location header에 변경된 URI를 적어 줘야 합니다.)
500 서버에 문제가 있을 경우 사용하는 응답 코드

 

7.  필드명에 대소문자 규칙 적용

어플리케이션 내에서 모든 대/소문자 규칙을 따를 수 있지만 어플리케이션 전체에서 일관성을 유지해야 함. 요청 본문 또는 응답 유형이 JSON인 경우 일관성을 유지하기 위해 카멜 표기법(camelCase)을 준수 할 것

 

8. 검색, 정렬, 필터링 그리고 페이징을 위한 규칙 사용

서버에 대한 요청은 하나의 데이터셋으로 처리되는 단순한 쿼리로 진행해야함. 예를 들어 GET 메소드 API로 검색, 정렬, 필터링, 페이징등의 쿼리 매개변수 추가는 다음의 예처럼 처리 권장

상태 코드 설명
Sorting - 예를들어 클라이언트가 정렬된 회사 목록을 가져오려는 경우 다음의 예처럼 처리 
- e.g. GET /companies?sort=rank_asc 
Filtering  - 데이터셋의 데이터를 필터링 할 때, 다양한 쿼리 파라미터를 통해 필터링 처리 가능
- e.g GET /companies?category=banking&location=india 
  (컴퍼니의 카테고리를 은행으로 정하고 은행이 위치한 장소를 인도로 필터 처리)
Searching - 검색은 다음의 예제와 같이 표현
- e.g. 
GET /companies?search=Digital
Pagination - 페이징 처리 예제
- e.g. Eg. GET 
/companies?page=23


9. API 버전 관리

  • API 버전 관리를 반드시 필수로 하고, 버전이 API는 릴리즈 하지 말 것
  • 간단한 서수를 표현하고 2.5등과 같은 점 표기법은 사용하지 말 것
  • 일반적으로 버전은 'v' + 숫자로 표기 
  • /blog/api/v1
  • http://api.yourservice.com/v1/companies/34/employees

사실 Version 관련해서는 예 처럼 URL에 버전을 표기하는 방식이외에도 아래와 같이 HTTP 헤더, Http 쿼리 파라미터를 통해 넘기는 방식등이 있다. 이런 방법에 대해서 기회가 되면 Spring Boot로 다양한 예제를 만들어 포스팅 하도록 하겠다.

구분 설명
HTTP 쿼리 파라미터 - HTTP 요청에 추가된 쿼리 문자열 내에 매개 변수를 사용하여 리소스의 버전을 지정
- https://adventure-works.com/customers/3?version=2
HTTP 헤더를 통한 버전 관리 - HTTP의 헤더에 리소스 버전(API 버전)을 지정
- GET https://adventure-works.com/customers/3 HTTP/1.1
Custom-Header: api-version=1

 

 

10. HATEOAS(Hypermedia as the Engine of Application State) 적용

REST를 실행하는 기본적인 목적 중 하나는 URI 체계에 대해 미리 알고 있지 않아도 전체 리소스 집합을 탐색할 수 있어야 하기 때문이다. 각 HTTP GET 요청은 응답에 포함된 하이퍼링크를 통해 요청된 개체와 직접 관련된 리소스를 찾는 데 필요한 정보를 반환해야 하며, 이러한 각 리소스에 대해 사용할 수 있는 작업을 설명하는 정보도 제공되어야 한다. 이 원칙을 HATEOAS(Hypertext as the Engine of Application State)라 한다. 시스템은 실질적으로 상태 시스템으로서, 각 요청에 대한 응답은 한 상태에서 다른 상태로 바꾸는 데 필요한 정보를 포함하고 있으며, 다른 정보는 필요하지 않다.

  • HATEOAS 예시(주문시 주문자 정보와 그 주문자의 상세 정보를 볼 수 있는 페이지를 링크로 넘김)
    {
      "orderID":3,
      "productID":2,
      "quantity":4,
      "orderValue":16.60,
      "links":[
        {
          "rel":"customer",
          "href":"https://adventure-works.com/customers/3",
          "action":"GET",
          "types":["text/xml","application/json"]
        },
        {
          "rel":"customer",
          "href":"https://adventure-works.com/customers/3",
          "action":"PUT",
          "types":["application/x-www-form-urlencoded"]
        },
        {
          "rel":"customer",
          "href":"https://adventure-works.com/customers/3",
          "action":"DELETE",
          "types":[]
        },
        {
          "rel":"self",
          "href":"https://adventure-works.com/orders/3",
          "action":"GET",
          "types":["text/xml","application/json"]
        },
        {
          "rel":"self",
          "href":"https://adventure-works.com/orders/3",
          "action":"PUT",
          "types":["application/x-www-form-urlencoded"]
        },
        {
          "rel":"self",
          "href":"https://adventure-works.com/orders/3",
          "action":"DELETE",
          "types":[]
        }]
    }
    이 응답에는 사람의 이름뿐만 아니라 그 사람의 이름으로 참조해야 하는 관계된 URL까지 링크로 제공해 주고 있다 
    • rel은 관계를 의미. 이 예제에서 사용한 'self'라는 의미는 같은 웹 사이트를 사용하는 참조 하이퍼링크라는 뜻임 예를 들어 주문에 "rel":"customer" 관계가 있을 수 있으며 주문을 고객과 연결할 수 있음
    • href는 리소스를 고유하게 정의하는 완전한 URL임
    • HTTP 메서드 및 지원되는 MIME 형식이 포함됨. 이 모든 정보가 있어야 클라이언트 애플리케이션이 작업을 호출할 수 있음

 

11. JSON을 통한 에러 응답 처리

API는 항상 자체 필드 집합에서 오류 메시지를 반환하도록 적극 권장. JSON 오류 본문은 개발자에게 유용한 오류 메시지, 고유한 오류 코드(문서등을 통해 자세한 내용을 찾을 수 있게해야 함) 및 가능한 자세한 설명 등 몇 가지 사항을 제공해야 함

좋은 오류 메시지 응답은 다음과 같음
{
    "코드": 1234,
    "message" : "예기지 않은 오류가 발생했습니다 .",
    "description" : "오류에 대한 자세한 내용은 xxxx를 참조."
}

 

RESTful API 작성 예시

  • URI는 리소스 식별이 유추 될 수 있도록 작성되어야 함

    http(s)://{Domain name (:Port #)}/{A value indicating REST API}/{API version}/{path for identifying a resource}

    http(s)://{Domain name indicating REST API(:Port #)}/{API version}/{path for identifying a resource}
    • http://example.com/api/v1/members/M000000001 
    • http://api.example.com/v1/members/M000000001

 

결론

RESTful 설계에 대한 표준은 강제적이지는 않지만 올바른 유추 가능한 API 설계 및 작성을 위해 그 표준 작성 및 준수에 대한 강제성이 필요하다고 생각한다.

 

<참고> HTTP 응답 상태 코드

  • 1xx (Information response) - 상태코드가 1로 시작하는 경우 서버가 요청을 받았으며 서버에 연결된 클라이언트는 작업을 계속 진행하라는 의미. 1번대 상태코드는 HTTP 1.0에서는 지원하지 않음
    • 100 Continue - 진행중임을 나타내는 응답코드임. 현재까지의 진행상태에 문제가 없으며 클라이언트가 계속해서 요청을 하거나 이미 요청을 완료한 경우에는 무시해도 되는 것을 알려줌
    • 101 Switching Protocol - 이 코드는 클라이언트에 의해 보낸 업그레이드 요청 헤더에 대한 응답으로 보냄. 이 코드는 클라이어언트가 보낸 Upgrade 요청 헤더에 대한 응답에 들어가며 서버에서 프로토콜을 변경할 것임을 알려줌. 해당 코드는 Websocket 프로토콜 전환시에 사용됨
    • 102 Processing(WebDAV) - 이 코드는 서버가 요청을 수신하였으며 이를 처리하고 있지만 아직 제대로 된 응답을 알려줄 수 없음을 알려줌
  • 2xx (Success category) - 2xx번대 응답 코드는 클라이언트 요청이 서버에서 성공적으로 진행됬다는 의미
    • 200 ok - GET, PUT 혹은 POST 요청에 대한 성공 응답 코드
    • 201 Created - 요청이 성공적이었으며 그 결과로 새로운 리소스가 생성되었다는 응답. 이 응답은 일반적으로 POST 또는 일부 PUT 요청에 대응
    • 202 Accepted -  요청은 수신하였지만 그에 대한 후속 액션을 할 수 없다는 코드. 이 응답은 요청 처리에 대한 결과를 이후에 HTTP로 비동기 응답을 보내는 것에 대해서 명확하게 명시하지 않음. 이것은 다른 프로세스에서 처리 또는 서버가 요청을 다루고 있거나 배치 프로세스를 하고 있는 경우를 위해 만들어짐
    • 203 Non-Authoritative Information - 이 응답 코드는 돌려받은 메타 정보 세트가 오리진 서버의 것과 일치하지 않지만 로컬이나 서드 파티 복사본에서 모아졌음을 의미함. 이러한 조건에서는 응답이 아니라 200 OK 응답을 반드시 우선 함
    • 204 No Content - 요청에 대해서 보내 줄 수 있는 콘텐츠가 없지만, 헤더는 의미있을 수 있음. 사용자-에이전트는 리소스가 캐시된 헤더를 새로운 것으로 업데이트 할 수 있음
    • 205 Reset Content - 이 응답 코드는 요청을 완수한 이후에 사용자 에이전트에게 이 요청을 보낸 문서 뷰를 리셋하려고 알려줌
    • 206 Partial Content - 이 응답 코드는 클라이언트에서 복수의 스트림을 분할 다운로드를 하고자 범위 헤더를 전송했기 때문에 사용됨. 클라이언트가 이어받기를 시도하면 웹서버가 이에 대한 응답코드로 "206 Partial Content"와 함께 Range 헤더에 명시된 데이터의 부분(byte) 부터 전송
    • 207 Multi-Status - 멀티-상태 응답은 여러 리소스가 여러 상태 코드인 상황이 적절한 경우에 해당되는 정보를 전달. 해당 코드는 WebDAV(Web Distributed Authoring and Versioning)에 사용됨
    • 208 ALREADY REPORTED - propstat(property와 status의 합성어) 응답 속성으로 동일 컬렉션으로 바인드된 복수의 내부맴버를 반복적으로 열거하는 것을 피하기 위해 사용. 해당 코드는 DAV에 사용
    • 226 IM Used(HTTP Delta encoding) - 서버가 GET 요청에 대한 리소스의 의무를 다 했고, 그리고 응답이 하나 또는 그 이상의 인스턴스 조작이 현재 인스턴스에 적용이 되었음을 알려줌
  • 3xx: Redirection message 
    • 300 Multiple Choice - 요청에 대해서 하나 이상의 응답이 가능. 사용자 에이전트 또는 사용자는 그중에 하나를 반드시 선택해야 함. 응답 중 하나를 선택하는 방법에 대한 표준화 된 방법은 존재하지 않음
    • 301 Moved Permanently - 이 응답 코드는 요청한 리소스의 URI가 변경되었음을 의미. 새로운 URI가 응답에서 아마도 주어 질 수 있음
    • 302 Found - 이 응답 코드는 요청한 리소스의 URI가 일시적으로 변경되었음을 의미. 새롭게 변경된 RUI는 나중에 만들어 질 수 있음. 그러므로 클라이언트는 향후의 요청도 반드시 동일한 URI로 해야 함
    • 304 Not Modified - 이것은 캐시를 목적으로 사용됨. 이 코드는 클라이언트에게 응답이 수정되지 않았음을 알려주며, 그러므로  클라이언트는 계속해서 응답의 캐시된 버전을 사용 할 수 있음
    • 305 Use Proxy - 이전 버전의 HTTP 기술 사양에서 정의되었으며, 요청한 응답은 반드시 프록시를 통해서 접속해야 하는 것을 알려 줌. 이 코드는 프록시의 in-band 설정에 대한 보안상의 걱정으로 인해 사라지고 있는 추세임
    • 306 unused - 이 응답 코드는 더이상 사용되지 않으며, 현재는 추후 사용을 위해 예약되어 있는 상태임. 
    • 307 Temporary Redirect - 클라이언트가 요청한 리소스가 다른 URI에 있으며, 이전 요청과 동일한 메소드를 사용하여 요청해야 할 때 서버가 클라이언트에 이 응답을 직접 보냄. 이 응답코드는 302 Found HTTP 응답 코드와 동일한 의미를 가지고 있으며, 사용자 에이전트가 반드시 사용된 HTTP 메소드를 변경하지 말아야 하는 점만 다름. 만약 첫 요청에 POST가 사용되었으면 두번째 요청에도 반드시 POST가 적용되어야 함
    • 308 Permanent Redirect - 이 응답코드는 요청하는 리소스가 HTTP 응답 헤더의 Location에 명시된 URI에 위치하고 있음을 의미함. 301 Moved Permanently HTTP 응답 코드와 동일한 의미
  • 4xx: Client error responses 
    • 400 Bad Request - 이 응답코드는 잘못된 문법으로 인하여 서버가 요청을 의미할 수 없음을 의미
    • 401 Unauthorized - 비록 HTTP 표준에서는 "미승인(unauthorized)"를 명확히 하고 있지만, 의미상 이 응답은 "비승인(unauthenticated)"을 의미함. 클라이언트는 요청한 응답을 받기 위해서 반드시 스스로 인증해야 함
    • 402 Payment Required - 이 응답 코드는 디지털 결제 시스템에 사용되기 위해 계획되었었으나 현재 사용되고 있지 않음.
    • 403 Forbidden - 클라이언트가 컨텐츠에 접근할 권한을 가지고 있지 않음.
    • 404 Not Found - 클라이언트의 요청 리소스를 서버가 찾을 수 없을 때. 브라우저에서는 알려주지 않은 URL을 의미 
    • 405 Method Not Allowed - 요청한 메소드는 서버에서 알고 있지만, 제거되었고 사용할 수 없는 경우
    • 406 Not Acceptable - 이 응답은 서버가 서버 주도 콘텐츠 협상을 수행한 이후, 사용자 에이전트에서 정해진 규격에 따른 어때한 컨텐츠도 찾지 못했을 때 웹 서버가 보냄
    • 407 Proxy Authentication Required - 401과 유사하지만 프록시에 의해 완료된 인증 필요
    • 408 Request Timeout - 지정된 요청 응답시간을 초과한 경우 발생
    • 409 Conflit - 요청이 현재 서버의 상태와 충돌시 보냄
    • 410 Gone - 요청 컨텐츠가 서버에서 완전 삭제되었을때 발생
    • 411 Length Required - 서버에서 필요로 하는 Content-Length 헤더 필드가 정의되지 않는 요청이 들어온 경우
    • 412 Precondition Failed - 클라이언트 헤더에 정의된 조건과 서버에 정의된 조건이 일치하지 않을 때
    • 413 Payload Too Large - 요청 엔티티가 서버에서 정의된 엔티티보다 클때
    • 414 URI Too Long - 클라이언트가 요청한 URI가 서버에서 처리 할 수 있는 길이보다 길때
    • 415 Unsupported Media Type - 요청 미디어 포맷이 서버에서 지원하지 않는 타입일때
    • 416 Requested Range Not Satisfiable - Range 헤더 필드에  정의된 지정 범위에 있지 않을 때
    • 417 Expectation Failed - Expect 요청 헤더 필드로 요청한 예상이 서버에서 적당하지 않음을 알려 줄때
  • 5xx : Server Error Response
    • 500 Internal Server Error - 웹서버에 에러 발생, 원인은 불명
    • 501 Not Implemented - 클라이언트의 요청을 서버가 이행하는데 필요한 기능을 지원하지 않고 있음
    • 502 Bad Gateway - 서버가 게이트웨어로부터 잘못된 응답을 수신했음. 인터넷상에서 서버가 다른 서버로부터 유효하지 않은 응답을 받은 경우 발생
    • 503 Service Unavailable - 서버가 요청 처리를 위한 준비가 되어 있지 않은 상태. 서버가 재 기동 중이거나 과부하로 응답 처리가 되지 못함
    • 504 Gateway timeout - 웹 페이지를 로드하거나 브라우저에서 다른 요청을 태우려는 동안 한 서버가 엑세스하고 있는 다른 서버에서 적시에 응답을 받지 못했을 경우 발생
    • 505 Http Version Not Supported - 서버에서 지원되지 않는 HTTP 버전을 클라이언트가 요청. 
    • 506 Variant Also Negotiates - 서버 내부 구성 오류
    • 511 Network Authentication Required - 클라이언트가 네트워크 억세스를 위해 인증이 필요 할 때

 

반응형

'Application Modernization > Others' 카테고리의 다른 글

현재 OS에 열린 포트 확인  (0) 2021.10.13
Swagger UI 사용법  (1) 2021.07.08