44์žฅ REST API

REST API๋ž€?

  • REST๋Š” ๋ฌด์—‡์ธ๊ฐ€?

    • REpresentational State Transfer์˜ ์ค„์ž„๋ง.

    • HTTP/1.0 ๊ณผ 1.1 ์ŠคํŽ™ ์ž‘์„ฑ ๋ฐ ์•„ํŒŒ์น˜ HTTP ์„œ๋ฒ„ ํ”„๋กœ์ ํŠธ์˜ ๊ณต๋™ ์„ค๋ฆฝ์ž ๋กœ์ด ํ•„๋”ฉ์˜ ๋…ผ๋ฌธ์—์„œ ์ฒ˜์Œ ์†Œ๊ฐœ๋˜์—ˆ๋‹ค.

    • HTTP ํ”„๋กœํ† ์ฝœ์˜ ์žฅ์ ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์•„ํ‚คํ…์ณ๋กœ ์†Œ๊ฐœ๋˜์–ด HTTP ํ”„๋กœํ† ์ฝœ์„ ์˜๋„์— ๋งž๊ฒŒ ๋””์ž์ธํ•˜๋„๋ก ์œ ๋„ํ•˜๊ณ  ์žˆ๋‹ค.

  • ์—„๊ฒฉํ•œ ์˜๋ฏธ vs ๊ฐ„๋‹จํ•œ ์˜๋ฏธ

    • ์—„๊ฒฉํ•œ ์˜๋ฏธ ๋„คํŠธ์›Œํฌ ์•„ํ‚คํ…์ณ ์›๋ฆฌ์˜ ๋ชจ์Œ, ์ฆ‰ ์ž์›์„ ์ •์˜ํ•˜๊ณ  ์ž์›์— ๋Œ€ํ•œ ์ฃผ์†Œ๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ „๋ฐ˜์„ ์˜๋ฏธํ•œ๋‹ค.

    • ๊ฐ„๋‹จํ•œ ์˜๋ฏธ ์›น ์ƒ์˜ ์ž๋ฃŒ๋ฅผ HTTP ์œ„์—์„œ ๋ณ„๋„์˜ ์ „์†ก๊ณ„์ธต ์—†์ด ์ „์†กํ•˜๊ธฐ ์œ„ํ•œ ์•„์ฃผ ๊ฐ„๋‹จํ•œ ์ธํ„ฐํŽ˜์ด์Šค

      • SOAP(Simple Object Access Protocol : HTTP, HTTPS ๋“ฑ์„ ํ†ตํ•ด XML ๊ธฐ๋ฐ˜ ๋ฉ”์„ธ์ง€๋ฅผ ๊ตํ™˜ํ•˜๋Š” ํ”„๋กœํ† ์ฝœ) ์ด๋‚˜ ์ฟ ํ‚ค๋ฅผ ํ†ตํ•œ ์„ธ์…˜ ํŠธ๋ž™ํ‚น ๊ฐ™์€ ์ „์†ก๊ณ„์ธต ๊ฒƒ๋“ค ์—†์ด ํ†ต์‹ 

  • RESTFul๊ณผ REST API๋Š” ๋ฌด์—‡์ธ๊ฐ€?

    • REST์˜ ๊ธฐ๋ณธ ์›์น™์„ ์„ฑ์‹คํžˆ ์ง€ํ‚จ ์„œ๋น„์Šค ๋‹ค์ง€์ธ์„ RESTfulํ•˜๋‹ค๊ณ  ํ‘œํ˜„ํ•œ๋‹ค.

    • REST๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„œ๋น„์Šค API๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

REST๋Š” HTTP๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์˜ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ์‹์„ ๊ทœ์ •ํ•œ ์•„ํ‚คํ…์ณ๊ณ , REST API๋Š” REST๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„œ๋น„์Šค API๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

44.1 REST API์˜ ๊ตฌ์„ฑ

REST API๋Š” ์ž์›(resource), ํ–‰์œ„(verb), ํ‘œํ˜„(representation)์˜ ์„ธ๊ฐ€์ง€ ์š”์†Œ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. REST๋Š” ์ž์ฒด ํ‘œํ˜„ ๊ตฌ์กฐ๋กœ ๊ตฌ์„ฑ๋˜์–ด REST API ๋งŒ์œผ๋กœ HTTP ์š”์ฒญ์˜ ๋‚ด์šฉ์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ตฌ์„ฑ์š”์†Œ
๋‚ด์šฉ
ํ‘œํ˜„๋ฐฉ๋ฒ•

์ž์›

์ž์›

URI(์—”๋“œํฌ์ธํŠธ)

ํ–‰์œ„

์ž์›์— ๋Œ€ํ•œ ํ–‰์œ„

HTTP ์š”์ฒญ ๋ฉ”์„œ๋“œ

ํ‘œํ˜„

์ž์›์— ๋Œ€ํ•œ ํ–‰์œ„์˜ ๊ตฌ์ฒด์  ๋‚ด์šฉ

ํŽ˜์ด๋กœ๋“œ

  • ํŽ˜์ด๋กœ๋“œ : ํฐ ๋ฐ์ดํ„ฐ ์ค‘์— 'ํฅ๋ฏธ์žˆ๋Š”' ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ๋ณ„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ.

    • ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์ฃผ๋กœ ๋ฉ”์„ธ์ง€ ํ”„๋กœํ† ์ฝœ ์ค‘์— ํ”„๋กœํ† ์ฝœ ์˜ค๋ฒ„ํ—ค๋“œ์™€ ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ(์ฆ‰ ํŽ˜์ด๋กœ๋“œ)๋ฅผ ๊ตฌ๋ถ„ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค

    • ์˜ˆ์‹œ - JSON ํ˜•์‹์˜ ์›น ์„œ๋น„์Šค ์‘๋‹ต

    {
      "status": "OK",
      "data": {
        "message": "Hello, world!"
      }
    }

    ์—ฌ๊ธฐ์—์„œ "Hello, world!"๊ฐ€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ด€์‹ฌ์„ ๊ฐ€์ง€๋Š” ํŽ˜์ด๋กœ๋“œ์ด๊ณ , ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์€ ์ค‘์š”ํ•˜๊ธด ํ•˜์ง€๋งŒ ํ”„๋กœํ† ์ฝœ ์˜ค๋ฒ„ํ—ค๋“œ์ด๋‹ค. ์ถœ์ฒ˜ : [wiki]https://ko.wikipedia.org/wiki/%ED%8E%98%EC%9D%B4%EB%A1%9C%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)

44.2 REST API ์„ค๊ณ„ ์›์น™

REST ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ธฐ๋ณธ์ง์ธ ์›์น™์€ ๋‘๊ฐ€์ง€์ด๋‹ค!!

1. URI๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ํ‘œํ˜„ํ•˜๋Š”๋ฐ ์ง‘์ค‘ํ•œ๋‹ค.
2. HTTP ์š”์ฒญ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ–‰์œ„๋ฅผ ์ •์˜ํ•œ๋‹ค.
  1. URI๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ํ‘œํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

#bad
GET /getTodos/1    - (1)๋ฒˆ ์˜ˆ์‹œ
GET /todos/show/1  - (2)๋ฒˆ ์˜ˆ์‹œ

# good
GET /todos/1

URI๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ํ‘œํ˜„ํ•˜๋Š”๋ฐ์— ์ค‘์ ์„ ๋‘์–ด์•ผ ํ•œ๋‹ค.

  • (1)๋ฒˆ ์˜ˆ์‹œ -> ์˜ˆ์‹œ์ฒ˜๋Ÿผ get ๊ฐ™์€ ํ–‰์œ„์— ๋Œ€ํ•œ ํ‘œํ˜„์ด ๋“ค์–ด๊ฐ€์„œ๋Š” ์•ˆ๋œ๋‹ค

  • (2)๋ฒˆ ์˜ˆ์‹œ -> ๋ฆฌ์†Œ์Šค๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ์ด๋ฆ„์€ ๋™์‚ฌ๋ณด๋‹ค๋Š” ๋ช…์‚ฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

  1. ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ํ–‰์œ„๋Š” HTTP ์š”์ฒญ ๋ฉ”์„œ๋“œ๋กœ ํ‘œํ˜„ํ•œ๋‹ค.

HTTP ์š”์ฒญ ๋ฉ”์„œ๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์—๊ฒŒ ์š”์ฒญ์˜ ์ข…๋ฅ˜์™€ ๋ชฉ์ (๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ํ–‰์œ„)์„ ์•Œ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

HTTP ์š”์ฒญ ๋ฉ”์„œ๋“œ
์ข…๋ฅ˜
๋ชฉ์ 
ํŽ˜์ด๋กœ๋“œ

GET

index / retrieve

๋ชจ๋“  ํŠน์ • ๋ฆฌ์†Œ์Šค ์ทจ๋“

X

POST

create

๋ฆฌ์†Œ์Šค ์ƒ์„ฑ

O

PUT

replace

๋ฆฌ์†Œ์Šค์˜ ์ „์ฒด ๊ต์ฒด

O

PATCH

modify

๋ฆฌ์†Œ์Šค์˜ ์ผ๋ถ€ ์ˆ˜์ •

O

DELETE

delete

๋ชจ๋“  / ํŠน์ • ๋ฆฌ์†Œ์Šค ์‚ญ์ œ

X

  # bad
  GET /todos/delete/1 - (1)๋ฒˆ ์˜ˆ์‹œ

  # good
  DELETE /todos/1

๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ํ–‰์œ„๋Š” HTTP ์š”์ฒญ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ‘œํ˜„ํ•˜๋ฉฐ, URI์— ํ‘œํ˜„ํ•˜์ง€ ์•Š๋Š”๋‹ค.

  • (1)๋ฒˆ ์˜ˆ์‹œ - GET์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์ทจ๋“ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. ์‚ญ์ œ ์š”์ฒญ์„ ํ•˜๋ ค๋ฉด DELETE ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

44.3 REST API ์‹ค์Šต

44.3.1 ~ 44.3.3 JSON Serverํ™˜๊ฒฝ ์„ธํŒ… (์ƒ๋žต)

  • ๋‹ค์Œ JSON ํŒŒ์ผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ์ค€์œผ๋กœ todo์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ CRUD ํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋ฒ„๋ผ๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž.

{
  "todos": [
    {
      "id": 1,
      "content": "JS",
      "completed": true
    },
    {
      "id": 2,
      "content": "React",
      "completed": false
    },
    {
      "id": 1,
      "content": "FrontEnd",
      "completed": false
    }
  ]
}

44.3.4 GET ์š”์ฒญ

  • ๋ชจ๋“  todos ๋ฆฌ์†Œ์Šค๋ฅผ ์ทจ๋“ ํ•  ๋•Œ

    const xhr = new XMLHttpRequest();
    
    /**G
     * 1. ํ–‰์œ„๋Š” ๋ฉ”์„œ๋“œ๋กœ GET ์š”์ฒญ์œผ๋กœ ์ทจ๋“ํ•˜๊ฒ ๋‹ค
     * 2. ๋ฆฌ์†Œ์Šค๋Š” URI๋กœ ํ‘œํ˜„, todos ๋ฆฌ์†Œ์Šค๋ฅผ ์ทจ๋“ํ•˜๊ฒ ๋‹ค(index)
     */
    xhr.open("GET", "/todos");
    
    xhr.send();
    
    xhr.onload = () => {
      if (xhr.status === 200) {
        console.log(xhr.response);
      } else {
        console.error("Error", xhr.status, xhr.statusText);
      }
    };
    • response

      {
        "todos": [
          {
            "id": 1,
            "content": "JS",
            "completed": true
          },
          {
            "id": 2,
            "content": "React",
            "completed": false
          },
          {
            "id": 3,
            "content": "FrontEnd",
            "completed": false
          }
        ]
      }
  • ํŠน์ • todos ๋ฆฌ์†Œ์Šค๋ฅผ ์ทจ๋“

    const xhr = new XMLHttpRequest();
    
    /**
     * 1. ํ–‰์œ„๋Š” ๋ฉ”์„œ๋“œ๋กœ GET ์š”์ฒญ์œผ๋กœ ์ทจ๋“ํ•˜๊ฒ ๋‹ค
     * 2. ๋ฆฌ์†Œ์Šค๋Š” URI๋กœ ํ‘œํ˜„, todos/1 ๋กœ id:1์ธ todo ๋ฆฌ์†Œ์Šค๋ฅผ ์ทจ๋“ํ•˜๊ฒ ๋‹ค
     *
     * todos ๋ฆฌ์†Œ์Šค์—์„œ ํŠน์ • todo๋ฅผ ์ทจ๋“(retrieve)
     */
    xhr.open("GET", "/todos/1");
    
    xhr.send();
    
    xhr.onload = () => {
      if (xhr.status === 200) {
        console.log(xhr.response);
      } else {
        console.error("Error", xhr.status, xhr.statusText);
      }
    };
    • response

      {
        "todos": [
          {
            "id": 1,
            "content": "JS",
            "completed": true
          }
        ]
      }

44.3.5 POST ์š”์ฒญ

const xhr = new XMLHttpRequest();

/**
 * 1. ํ–‰์œ„๋Š” ๋ฉ”์„œ๋“œ๋กœ POST ์š”์ฒญ์œผ๋กœ ์ƒ์„ฑํ•˜๊ฒ ๋‹ค
 * 2. ๋ฆฌ์†Œ์Šค๋Š” URI๋กœ ํ‘œํ˜„, ์ƒˆ๋กœ์šด todo๋ฅผ ์ƒ์„ฑํ•˜๊ฒ ๋‹ค
 */
xhr.open("POST", "/todos");

// ์š”์ฒญ ๋ชธ์ฒด์— ๋‹ด์•„ ์„œ๋ฒ„๋กœ ๋ณด๋‚ผ ํŽ˜์ด๋กœ๋“œ์˜ MIME ํƒ€์ž… ์ง€์ •
xhr.setRequestHeader("Content-Type", "application/json");

// ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋‹ด์•„์„œ ์„œ๋ฒ„๋กœ ์ „์†ก
xhr.send(JSON.stringify({ id: "4", content: "Angular", completed: false }));

xhr.onload = () => {
  if (xhr.status === 200) {
    console.log(xhr.response);
  } else {
    console.error("Error", xhr.status, xhr.statusText);
  }
};
  • response

    {
      "todos": [
        {
          "id": 1,
          "content": "JS",
          "completed": true
        },
        {
          "id": 2,
          "content": "React",
          "completed": false
        },
        {
          "id": 3,
          "content": "FrontEnd",
          "completed": false
        },
        {
          "id": 4,
          "content": "Angular",
          "completed": false
        }
      ]
    }

44.3.6 PUT ์š”์ฒญ

const xhr = new XMLHttpRequest();

/**
 * 1. ํ–‰์œ„๋Š” ๋ฉ”์„œ๋“œ๋กœ PUT ์š”์ฒญ์œผ๋กœ ๋ฆฌ์†Œ์Šค์ „์ฒด๋ฅผ ๊ต์ฒดํ•˜๊ฒ ๋‹ค
 * 2. ๋ฆฌ์†Œ์Šค๋Š” URI๋กœ ํ‘œํ˜„, id๋กœ todo๋ฅผ ํŠน์ •ํ•˜์—ฌ id๋ฅผ ์ œ์™ธํ•œ ๋ฆฌ์†Œ์Šค ์ „์ฒด๋ฅผ ๊ต์ฒด
 */
xhr.open("PUT", "/todos/4");

// ์š”์ฒญ ๋ชธ์ฒด์— ๋‹ด์•„ ์„œ๋ฒ„๋กœ ๋ณด๋‚ผ ํŽ˜์ด๋กœ๋“œ์˜ MIME ํƒ€์ž… ์ง€์ •
xhr.setRequestHeader("Content-Type", "application/json");

// ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋‹ด์•„์„œ ์„œ๋ฒ„๋กœ ์ „์†ก
xhr.send(JSON.stringify({ id: "4", content: "Svelte", completed: false }));

xhr.onload = () => {
  if (xhr.status === 200) {
    console.log(xhr.response);
  } else {
    console.error("Error", xhr.status, xhr.statusText);
  }
};
  • response

    {
      "todos": [
        {
          "id": 4,
          "content": "Svelte",
          "completed": false
        }
      ]
    }

44.3.7 PATCH ์š”์ฒญ

const xhr = new XMLHttpRequest();

/**
 * 1. ํ–‰์œ„๋Š” ๋ฉ”์„œ๋“œ๋กœ, PATCH ์š”์ฒญ์œผ๋กœ ๋ฆฌ์†Œ์Šค์ „์ฒด๋ฅผ ๊ต์ฒดํ•˜๊ฒ ๋‹ค
 * 2. ๋ฆฌ์†Œ์Šค๋Š” URI๋กœ ํ‘œํ˜„, id๋กœ todo๋ฅผ ํŠน์ •ํ•˜์—ฌ ์›ํ•˜๋Š” ๋ถ€๋ถ„๋งŒ ๊ต์ฒด
 */
xhr.open("PATCH", "/todos/2");

// ์š”์ฒญ ๋ชธ์ฒด์— ๋‹ด์•„ ์„œ๋ฒ„๋กœ ๋ณด๋‚ผ ํŽ˜์ด๋กœ๋“œ์˜ MIME ํƒ€์ž… ์ง€์ •
xhr.setRequestHeader("Content-Type", "application/json");

// ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋‹ด์•„์„œ ์„œ๋ฒ„๋กœ ์ „์†ก
xhr.send(JSON.stringify({ completed: true }));

xhr.onload = () => {
  if (xhr.status === 200) {
    console.log(xhr.response);
  } else {
    console.error("Error", xhr.status, xhr.statusText);
  }
};
  • response

    {
      "todos": [
        {
          "id": 2,
          "content": "React",
          "completed": true
        }
      ]
    }

44.3.8 DELETE ์š”์ฒญ

/**
 * 1. ํ–‰์œ„๋Š” ๋ฉ”์„œ๋“œ๋กœ DELETE ์š”์ฒญ์œผ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ญ์ œํ•˜๊ฒ ๋‹ค
 * 2. ๋ฆฌ์†Œ์Šค๋Š” URI๋กœ ํ‘œํ˜„, id๋กœ todo๋ฅผ ํŠน์ •ํ•˜์—ฌ ํ•ด๋‹น todo ์‚ญ์ œ
 */
xhr.open("PATCH", "/todos/4");

// ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋‹ด์•„์„œ ์„œ๋ฒ„๋กœ ์ „์†ก
xhr.send(JSON.stringify({ completed: true }));

xhr.onload = () => {
  if (xhr.status === 200) {
    console.log(xhr.response);
  } else {
    console.error("Error", xhr.status, xhr.statusText);
  }
};
  • response

    {}

Last updated