Rest API
기술

Rest API

작성일: 2022년 12월 02일0

REST API는 웹에서 사용되는 데이터나 자원(Resource)을 HTTP URI로 표현하고, HTTP 프로토콜을 통해 요청과 응답을 정의하는 방식입니다.

How to design an Rest API

Notion Image

Rest API는 위 그림과 같은 단계로 구성됩니다.

Level 0 : 1 URI, 1 HTTP method

level 0은 웹 메커니즘을 사용하지 않고 HTTP를 원격 통신을 위한 전송 시스템으로 사용합니다. RPC(Remote Precedure Call) 형태로 리소스 구분 없이 설계된 HTTP API입니다.

그저 단순하게 POX(Plain Old XML)를 주고 받는 RPC 스타일 시스템을 말하며 단 하나의 endpoint를 사용하고, 전달되는 서로 다른 매개변수를 통해 하나의 endpoint에서 여러 동작을 하게 됩니다. 매개 변수를 body로 전달하기 위해 HTTP method는 POST가 됩니다.

  • {
      "object": "block",
      "id": "7020626b-3db6-4ae6-a5cd-32e0ae08231d",
      "parent": {
        "type": "block_id",
        "block_id": "bddfd3ed-1621-4d37-ac06-41c94b5c5963"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Request",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Request",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    POST https://api/user
    {
      "function": "getUser",
      "arguments" [
        "1"
      ]
    }
  • {
      "object": "block",
      "id": "ab29875c-2bba-4997-9a1e-579f1658aff2",
      "parent": {
        "type": "block_id",
        "block_id": "6db4f515-3ad0-4c7f-af43-7ff2d42c714a"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Response",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Response",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    HTTP/1.1 200 OK
    {
      "result" {
      	"id": "1"
        "name": "modac",
      }
    }
  • {
      "object": "block",
      "id": "afb2f159-7420-41ce-b489-921f15e163ec",
      "parent": {
        "type": "block_id",
        "block_id": "bab386b9-ae2c-4e92-a1fb-d8abe40e2f01"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "CRUD",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "CRUD",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    CREATE : POST /api/user
    READ :   POST /api/user
    UPDATE : POST /api/user
    DELETE : POST /api/user

    위 예시에서는 HTTP 프로토콜을 사용하고 있는 것을 확인할 수 있습니다. 물론 이 경우, 해당 API를 REST API라고 할 수는 없으며, 0단계는 REST API를 작성하기 위한 기본 단계입니다.

    Level 1 : N URI, 2 HTTP method

    1단계에서는 개별 리소스(Resource)와의 통신을 준수해야 합니다. 모든 요청을 단일 서비스 endpoint로 보내는 것이 아니라 개별 리소스와 통신하게 됩니다. 리소스 별로 고유한 URI를 사용해서 식별합니다.

  • {
      "object": "block",
      "id": "a128764e-61d6-4fa4-a777-46094ebec984",
      "parent": {
        "type": "block_id",
        "block_id": "a542f61a-e88b-4106-a025-f331449e25d2"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Request",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Request",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    POST https://api/users/create
    {
      "name": "modac"
    }
  • {
      "object": "block",
      "id": "cc371cae-af43-4f4b-9105-b293b159b762",
      "parent": {
        "type": "block_id",
        "block_id": "65dba454-17fb-44a3-ad65-63658439476b"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Response",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Response",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    HTTP/1.1 200 OK
    {
      "result" {
        "error": "already exist member"
      }
    }
  • {
      "object": "block",
      "id": "3abc4cae-05e0-41ea-805c-a29668f0e7f4",
      "parent": {
        "type": "block_id",
        "block_id": "2b1c5a3a-b799-4d9d-b4e1-3481731573d3"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "CRUD",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "CRUD",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    CREATE : POST /api/users/create
    READ :   GET /api/users/1
    UPDATE : POST /api/users/update
    DELETE : POST /api/users/remove/1

    HTTP method는 GET과 POST만 사용하고 있고, Response에서는 error인 경우에도 Status Code를 200으로 전달하고 있습니다. 또 HTTP headers에 Content-Type이나 Cache 관련 정보를 제공하지 않습니다.

    Level 2 : N URI, 4 HTTP method

    2단계에서는 HTTP method인 GET, POST, PUT, DELETE를 사용해 CRUD를 나타내고 메시지에 Status Code도 담겨 반환합니다. GET은 상태를 변화시키지 않는 안전한 Action을 나타내고, 안전하게 얼마든지 호출할 수 있고 매번 같은 결과를 얻도록 합니다. 그리고 캐싱을 할 수 있어 사용자 입장에서 성능 향상도 느낄 수 있습니다.

  • {
      "object": "block",
      "id": "a0c37ced-97f8-4f00-a88a-85ce0fdc455d",
      "parent": {
        "type": "block_id",
        "block_id": "88b5679f-28bc-4768-ae41-e86ae7180a4b"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Request",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Request",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    PUT https://api/users
    {
      "name": "modac"
    }
  • {
      "object": "block",
      "id": "65f9b88a-0301-4ba7-a7e7-6aaf53aa88ed",
      "parent": {
        "type": "block_id",
        "block_id": "de61bcb5-092e-45fc-b251-1d54edd7bc31"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Response",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Response",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    HTTP/1.1 201 Created
    Content-Type: application/json
    {
      "result" {
        "id": "1",
        "name": "modac"
      }
    }
  • {
      "object": "block",
      "id": "1c80a951-872a-49ab-a9be-173027543b24",
      "parent": {
        "type": "block_id",
        "block_id": "a980d7f8-96b3-44d7-bec6-bb1a5d73360b"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "CRUD",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "CRUD",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    CREATE : POST /api/users
    READ :   GET /api/users/1
    UPDATE : PUT /api/users/1
    DELETE : DELETE /api/users/1
  • GET 메서드 같은 경우는 서버의 데이터를 변화시키지 않는 요청에 사용해야 합니다.
  • POST 메서드는 요청마다 새로운 리소스를 생성하고 PUT 메서드는 요청마다 같은 리소스를 반환합니다. 이렇게 매 요청마다 같은 리소스를 반환하는 특징을 멱등(idempotent)하다고 합니다. 그렇기 때문에 멱등성을 가지는 메서드 PUT과 그렇지 않은 메서드POST는 구분하여 사용해야 합니다.
  • PUT 메서드와 PATCH 메서드도 구분하여 사용해야 합니다. PUT은 교체, PATCH는 수정의 용도로 사용합니다.
  • API를 작성할 때, REST 성숙도 모델의 2단계까지 적용하면 대체적으로 잘 작성된 API라고 합니다.

    Level 3 : HATEOAS

    마지막 단계는 HATEOAS(Hypermedia As The Engine Of Application State)라는 약어로 표현되는 하이퍼미디어 컨트롤을 적용합니다. 3단계의 요청은 2단계와 동일하지만, 응답에는 리소스의 URI를 포함한 링크 요소를 삽입하여 작성해야 합니다.

    이때 응답에 들어가게 되는 링크 요소는 응답을 받은 다음에 할 수 있는 다양한 액션들을 위해 많은 하이퍼미디어 컨트롤을 포함하고 있습니다.

  • {
      "object": "block",
      "id": "192279ce-1664-4631-b83a-6cc73c943a56",
      "parent": {
        "type": "block_id",
        "block_id": "dc610b12-1fd9-472a-bbb0-fff42a16053e"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Request",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Request",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    GET https://api/
  • {
      "object": "block",
      "id": "ce403593-d9cc-47ea-8ce9-aa85d08e7133",
      "parent": {
        "type": "block_id",
        "block_id": "39823a43-ab08-475f-bf39-5522b6973339"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Response",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Response",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    HTTP/1.1 200 OK
    Content-Type: application/json
    {
      "/api/users",
      "/api/users/{userId}/roles",
      "/api/products",
      "/api/..."
    }
  • {
      "object": "block",
      "id": "9585b5d1-7826-494a-8960-7dea5a495708",
      "parent": {
        "type": "block_id",
        "block_id": "4c2d7b48-c0f5-4154-986d-4d8ae8395ab4"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Request",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Request",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    GET https://api/users/1
  • {
      "object": "block",
      "id": "d63fcb36-43d5-4841-944d-d914d2bbfb65",
      "parent": {
        "type": "block_id",
        "block_id": "0e8e076f-c4a4-4f14-97e1-25a77b61d148"
      },
      "created_time": "2026-07-01T14:50:00.000Z",
      "last_edited_time": "2026-07-01T14:50:00.000Z",
      "created_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "last_edited_by": {
        "object": "user",
        "id": "2ecd872b-594c-81f7-92e3-000210a8d473"
      },
      "has_children": false,
      "in_trash": false,
      "type": "heading_4",
      "heading_4": {
        "rich_text": [
          {
            "type": "text",
            "text": {
              "content": "Response",
              "link": null
            },
            "annotations": {
              "bold": false,
              "italic": false,
              "strikethrough": false,
              "underline": false,
              "code": false,
              "color": "default"
            },
            "plain_text": "Response",
            "href": null
          }
        ],
        "is_toggleable": false,
        "color": "default"
      },
      "archived": false
    }
    HTTP/1.1 200 OK
    Content-Type: application/json
    {
     "result" {
        "id": "1",
        "name": "modac",
        "nextActions": {
           "/api/users/{userId}/roles",
         }
      }
     "links" : {
    	"self" : {
    		"href" : "https://github.com/MODAC0"
          	"method" : "GET"
        }
     }
    }

    만약 클라이언트 개발자들이 응답에 담겨 있는 링크들을 눈여겨본다면, 이러한 링크들은 조금 더 쉽고, 효율적으로 리소스와 기능에 접근할 수 있게 하는 요소가 될 수 있습니다.

    구글의 REST API 작성 가이드라인을 통해 실제 활용되는 모범적인 사례를 확인해봅시다.

    Open API

    누구나 이용할 수 있지만 제한사항이 정해져 있는 API입니다.

    이때 제한사항 중 API Key가 존재하며 API Key는 로그인 시 필요한 Password의 개념입니다.