RESTλŠ” HTTPλ₯Ό 기반으둜 ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ²„μ˜ λ¦¬μ†ŒμŠ€μ— μ ‘κ·Όν•˜λŠ” 방식을 κ·œμ •ν•œ μ•„ν‚€ν…μ²˜κ³ , REST APIλŠ” RESTλ₯Ό 기반으둜 μ„œλΉ„μŠ€ APIλ₯Ό κ΅¬ν˜„ν•œ 것을 μ˜λ―Έν•œλ‹€.

🍭 44.1 RESA API의 ꡬ성

REST APIλŠ” μžμ›(resource), ν–‰μœ„(verb), ν‘œν˜„(representations)의 3가지 μš”μ†Œλ‘œ κ΅¬μ„±λœλ‹€. RESTλŠ” 자체 ν‘œν˜„ ꡬ쑰(self-de-scriptiveness)둜 κ΅¬μ„±λ˜μ–΄ REST API만으둜 HTTP μš”μ²­μ˜ λ‚΄μš©μ„ 이해할 수 μžˆλ‹€.

ꡬ성 μš”μ†Œλ‚΄μš©ν‘œν˜„ 방법
μžμ›(resource)μžμ›URI(μ—”λ“œν¬μΈνŠΈ)
ν–‰μœ„(verb)μžμ›μ— λŒ€ν•œ ν–‰μœ„HTTP μš”μ²­ λ©”μ„œλ“œ
ν‘œν˜„(representations)μžμ›μ— λŒ€ν•œ ν–‰μœ„μ˜ ꡬ체적 λ‚΄μš©νŽ˜μ΄λ‘œλ“œ

🍭 44.2 RESA API 섀계 원칙

  1. URIλŠ” λ¦¬μ†ŒμŠ€λ₯Ό ν‘œν˜„ν•΄μ•Ό ν•œλ‹€.

    # bad
    GET /getTodos/1
    GET /todos/show/1
    
    # good
    GET /todos/1
  2. λ¦¬μ†ŒμŠ€μ— λŒ€ν•œ ν–‰μœ„λŠ” HTTP μš”μ²­ λ©”μ„œλ“œλ‘œ ν‘œν˜„ν•œλ‹€.

    HTTP μš”μ²­ λ©”μ„œλ“œλŠ” ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ²„μ—κ²Œ μš”μ²­μ˜ μ’…λ₯˜μ™€ λͺ©μ (λ¦¬μ†ŒμŠ€μ— λŒ€ν•œ ν–‰μœ„)을 μ•Œλ¦¬λŠ” λ°©λ²•μœΌλ‘œ 주둜 5개의 μš”μ²­ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄ CRUDλ₯Ό κ΅¬ν˜„ν•œλ‹€.

    HTTP μš”μ²­ λ©”μ„œλ“œμ’…λ₯˜λͺ©μ νŽ˜μ΄λ‘œλ“œ
    GETindex/retrieveλͺ¨λ“ /νŠΉμ • λ¦¬μ†ŒμŠ€ 취득X
    POSTcreateλ¦¬μ†ŒμŠ€ 생성O
    PUTreplaceλ¦¬μ†ŒμŠ€μ˜ 전체 ꡐ체O
    PATCHmodifyλ¦¬μ†ŒμŠ€μ˜ 일뢀 μˆ˜μ •O
    DELETEdeleteλͺ¨λ“ /νŠΉμ • λ¦¬μ†ŒμŠ€ μ‚­μ œX
    # bad
    GET /todos/delete/1
    
    # good
    DELETE /todos/1

🍭 44.3 JSON Serverλ₯Ό μ΄μš©ν•œ REST API μ‹€μŠ΅

βœ” 44.3.1 JSON Server μ„€μΉ˜

$npm install json-server --sava-D

βœ” 44.3.2 db.json 파일 생성

## db.json

{
  "todos": [
    {
      "id": 1,
      "content": "HTML",
      "completed": true
    },
    {
      "id": 2,
      "content": "CSS",
      "completed": false
    },
    {
      "id": 3,
      "content": "Javascript",
      "completed": true
    }
  ]
}

βœ” 44.3.3 JSON Server μ‹€ν–‰

  • JSON Server β€”watch
    ## 기본포트(3000) μ‚¬μš© / watch μ˜΅μ…˜ 적용
    $json-server --watch db.json
    
    ## 포트 λ³€κ²½ / watch μ˜΅μ…˜ 적용
    $json-server --watch db.json --port 5000
  • npm start
    {
      "name": "json-server-exam",
      "version": "1.0.0",
      "scripts": {
        "start": "json-server --watch db.json"
      },
      "devDependencies": {
        "json-server": "^0.16.1"
      }
    }

βœ” 44.3.4 GET μš”μ²­

todos λ¦¬μ†ŒμŠ€μ—μ„œ λͺ¨λ“  todoλ₯Ό 취득(index)ν•œλ‹€.

<!DOCTYPE html>
<html>
<body>
  <pre></pre>
  <script>
    // XMLHttpRequest 객체 생성
    const xhr = new XMLHttpRequest();

    // HTTP μš”μ²­ μ΄ˆκΈ°ν™”
    // todos λ¦¬μ†ŒμŠ€μ—μ„œ λͺ¨λ“  todoλ₯Ό 취득(index)
    xhr.open('GET', '/todos');

    // HTTP μš”μ²­ 전솑
    xhr.send();

    // load μ΄λ²€νŠΈλŠ” μš”μ²­μ΄ μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλœ 경우 λ°œμƒν•œλ‹€.
    xhr.onload = () => {
      // status ν”„λ‘œνΌν‹° 값이 200이면 μ •μƒμ μœΌλ‘œ μ‘λ‹΅λœ μƒνƒœλ‹€.
      if (xhr.status === 200) {
        document.querySelector('pre').textContent = xhr.response;
      } else {
        console.error('Error', xhr.status, xhr.statusText);
      }
    };
  </script>
</body>
</html>

βœ” 44.3. POST μš”μ²­

todos λ¦¬μ†ŒμŠ€μ— μƒˆλ‘œμš΄ todoλ₯Ό μƒμ„±ν•œλ‹€. POST μš”μ²­μ‹œμ—λŠ” setRequestHeader λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μš”μ²­ λͺΈμ²΄μ— λ‹΄μ•„ μ„œλ²„λ‘œ 전솑할 νŽ˜μ΄λ‘œλ“œμ˜ MINE νƒ€μž…μ„ μ§€μ •ν•œλ‹€.

<!DOCTYPE html>
<html>
<body>
  <pre></pre>
  <script>
    // XMLHttpRequest 객체 생성
    const xhr = new XMLHttpRequest();

    // HTTP μš”μ²­ μ΄ˆκΈ°ν™”
    // todos λ¦¬μ†ŒμŠ€μ— μƒˆλ‘œμš΄ todoλ₯Ό 생성
    xhr.open('POST', '/todos');

    // μš”μ²­ λͺΈμ²΄μ— λ‹΄μ•„ μ„œλ²„λ‘œ 전솑할 νŽ˜μ΄λ‘œλ“œμ˜ MIME νƒ€μž…μ„ 지정
    xhr.setRequestHeader('content-type', 'application/json');

    // HTTP μš”μ²­ 전솑
    // μƒˆλ‘œμš΄ todoλ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•΄ νŽ˜μ΄λ‘œλ“œλ₯Ό μ„œλ²„μ— 전솑해야 ν•œλ‹€.
    xhr.send(JSON.stringify({ id: 4, content: 'Angular', completed: false }));

    // load μ΄λ²€νŠΈλŠ” μš”μ²­μ΄ μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλœ 경우 λ°œμƒν•œλ‹€.
    xhr.onload = () => {
      // status ν”„λ‘œνΌν‹° 값이 200(OK) λ˜λŠ” 201(Created)이면 μ •μƒμ μœΌλ‘œ μ‘λ‹΅λœ μƒνƒœλ‹€.
      if (xhr.status === 200 || xhr.status === 201) {
        document.querySelector('pre').textContent = xhr.response;
      } else {
        console.error('Error', xhr.status, xhr.statusText);
      }
    };
  </script>
</body>
</html>

βœ” 44.3.6 PUT μš”μ²­

νŠΉμ • λ¦¬μ†ŒμŠ€ 전체λ₯Ό ꡐ체할 λ•Œ μ‚¬μš©ν•œλ‹€.

<!DOCTYPE html>
<html>
<body>
  <pre></pre>
  <script>
    // XMLHttpRequest 객체 생성
    const xhr = new XMLHttpRequest();

    // HTTP μš”μ²­ μ΄ˆκΈ°ν™”
    // todos λ¦¬μ†ŒμŠ€μ—μ„œ id둜 todoλ₯Ό νŠΉμ •ν•˜μ—¬ idλ₯Ό μ œμ™Έν•œ λ¦¬μ†ŒμŠ€ 전체λ₯Ό ꡐ체
    xhr.open('PUT', '/todos/4');

    // μš”μ²­ λͺΈμ²΄μ— λ‹΄μ•„ μ„œλ²„λ‘œ 전솑할 νŽ˜μ΄λ‘œλ“œμ˜ MIME νƒ€μž…μ„ 지정
    xhr.setRequestHeader('content-type', 'application/json');

    // HTTP μš”μ²­ 전솑
    // λ¦¬μ†ŒμŠ€ 전체λ₯Ό κ΅μ²΄ν•˜κΈ° μœ„ν•΄ νŽ˜μ΄λ‘œλ“œλ₯Ό μ„œλ²„μ— 전솑해야 ν•œλ‹€.
    xhr.send(JSON.stringify({ id: 4, content: 'React', completed: true }));

    // load μ΄λ²€νŠΈλŠ” μš”μ²­μ΄ μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλœ 경우 λ°œμƒν•œλ‹€.
    xhr.onload = () => {
      // status ν”„λ‘œνΌν‹° 값이 200이면 μ •μƒμ μœΌλ‘œ μ‘λ‹΅λœ μƒνƒœλ‹€.
      if (xhr.status === 200) {
        document.querySelector('pre').textContent = xhr.response;
      } else {
        console.error('Error', xhr.status, xhr.statusText);
      }
    };
  </script>
</body>
</html>

βœ” 44.3.7 PATCH μš”μ²­

PATCHλŠ” νŠΉμ • λ¦¬μ†ŒμŠ€μ˜ 일뢀λ₯Ό μˆ˜μ •ν•  λ•Œ μ‚¬μš©ν•œλ‹€.

<!DOCTYPE html>
<html>
<body>
  <pre></pre>
  <script>
    // XMLHttpRequest 객체 생성
    const xhr = new XMLHttpRequest();

    // HTTP μš”μ²­ μ΄ˆκΈ°ν™”
    // todos λ¦¬μ†ŒμŠ€μ˜ id둜 todoλ₯Ό νŠΉμ •ν•˜μ—¬ completed만 μˆ˜μ •
    xhr.open('PATCH', '/todos/4');

    // μš”μ²­ λͺΈμ²΄μ— λ‹΄μ•„ μ„œλ²„λ‘œ 전솑할 νŽ˜μ΄λ‘œλ“œμ˜ MIME νƒ€μž…μ„ 지정
    xhr.setRequestHeader('content-type', 'application/json');

    // HTTP μš”μ²­ 전솑
    // λ¦¬μ†ŒμŠ€λ₯Ό μˆ˜μ •ν•˜κΈ° μœ„ν•΄ νŽ˜μ΄λ‘œλ“œλ₯Ό μ„œλ²„μ— 전솑해야 ν•œλ‹€.
    xhr.send(JSON.stringify({ completed: false }));

    // load μ΄λ²€νŠΈλŠ” μš”μ²­μ΄ μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλœ 경우 λ°œμƒν•œλ‹€.
    xhr.onload = () => {
      // status ν”„λ‘œνΌν‹° 값이 200이면 μ •μƒμ μœΌλ‘œ μ‘λ‹΅λœ μƒνƒœλ‹€.
      if (xhr.status === 200) {
        document.querySelector('pre').textContent = xhr.response;
      } else {
        console.error('Error', xhr.status, xhr.statusText);
      }
    };
  </script>
</body>
</html>

βœ” 44.3.8 DELETE μš”μ²­

todos λ¦¬μ†ŒμŠ€μ—μ„œ idλ₯Ό μ‚¬μš©ν•˜μ—¬ todoλ₯Ό μ‚­μ œν•œλ‹€.

<!DOCTYPE html>
<html>
<body>
  <pre></pre>
  <script>
    // XMLHttpRequest 객체 생성
    const xhr = new XMLHttpRequest();

    // HTTP μš”μ²­ μ΄ˆκΈ°ν™”
    // todos λ¦¬μ†ŒμŠ€μ—μ„œ idλ₯Ό μ‚¬μš©ν•˜μ—¬ todoλ₯Ό μ‚­μ œν•œλ‹€.
    xhr.open('DELETE', '/todos/4');

    // HTTP μš”μ²­ 전솑
    xhr.send();

    // load μ΄λ²€νŠΈλŠ” μš”μ²­μ΄ μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλœ 경우 λ°œμƒν•œλ‹€.
    xhr.onload = () => {
      // status ν”„λ‘œνΌν‹° 값이 200이면 μ •μƒμ μœΌλ‘œ μ‘λ‹΅λœ μƒνƒœλ‹€.
      if (xhr.status === 200) {
        document.querySelector('pre').textContent = xhr.response;
      } else {
        console.error('Error', xhr.status, xhr.statusText);
      }
    };
  </script>
</body>
</html>
profile
μ΄μ‚¬μ€‘μž…λ‹ˆλ‹€!🌟https://velog.io/@devkyoung2

0개의 λŒ“κΈ€

κ΄€λ ¨ μ±„μš© 정보