자습서: JavaScript를 사용하여 ASP.NET Core Web API 호출

작성자: Rick Anderson

이 자습서에서는 Fetch API를 사용하여 JavaScript로 ASP.NET Core 웹 API를 호출하는 방법을 보여줍니다.

필수 조건

JavaScript를 사용하여 웹 API 호출

이 섹션에서는 할 일 항목의 생성과 관리를 위한 양식이 포함된 HTML 페이지를 추가하게 됩니다. 이벤트 처리기는 페이지의 요소에 연결됩니다. 이벤트 처리기에 의해 웹 API의 작업 메서드에 대한 HTTP 요청이 발생합니다. Fetch API의 fetch 함수는 각 HTTP 요청을 시작합니다.

fetch 함수는 Promise 개체를 반환하는데, 해당 개체에는 Response 개체로 나타나는 HTTP 응답이 포함됩니다. 일반적인 패턴은 Response 개체에 대해 json 함수를 호출하여 JSON 응답 본문을 추출하는 것입니다. JavaScript는 웹 API 응답의 세부 정보를 토대로 페이지를 업데이트합니다.

가장 간단한 fetch 호출에서는 경로를 나타내는 단일 매개 변수가 허용됩니다. init 개체라고 하는 두 번째 매개 변수는 선택 사항입니다. init은 HTTP 요청 구성에 사용됩니다.

  1. 정적 파일을 제공하고 기본 파일 매핑을 사용하도록 앱을 구성합니다. 다음 강조 표시된 코드는 다음에서 필요합니다.Program.cs
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));

var app = builder.Build();

if (builder.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseDefaultFiles();
app.UseStaticFiles();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();
  1. 프로젝트 루트에서 wwwroot 폴더를 만듭니다.

  2. wwwroot 폴더 안에 css 폴더를 만듭니다.

  3. wwwroot 폴더 안에 js 폴더를 만듭니다.

  4. wwwroot 폴더에 명명된 index.html HTML 파일을 추가합니다. index.html의 콘텐츠를 다음 태그로 바꿉니다.

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>To-do CRUD</title>
        <link rel="stylesheet" href="css/site.css" />
    </head>
    <body>
        <h1>To-do CRUD</h1>
        <h3>Add</h3>
        <form action="javascript:void(0);" method="POST" onsubmit="addItem()">
            <input type="text" id="add-name" placeholder="New to-do">
            <input type="submit" value="Add">
        </form>
    
        <div id="editForm">
            <h3>Edit</h3>
            <form action="javascript:void(0);" onsubmit="updateItem()">
                <input type="hidden" id="edit-id">
                <input type="checkbox" id="edit-isComplete">
                <input type="text" id="edit-name">
                <input type="submit" value="Save">
                <a onclick="closeInput()" aria-label="Close">&#10006;</a>
            </form>
        </div>
    
        <p id="counter"></p>
    
        <table>
            <tr>
                <th>Is Complete?</th>
                <th>Name</th>
                <th></th>
                <th></th>
            </tr>
            <tbody id="todos"></tbody>
        </table>
    
        <script src="js/site.js" asp-append-version="true"></script>
        <script type="text/javascript">
            getItems();
        </script>
    </body>
    </html>
    
  5. wwwroot/css 폴더에 명명된 site.cssCSS 파일을 추가합니다 . 내용을 다음 스타일로 바꿉니다 site.css .

    input[type='submit'], button, [aria-label] {
        cursor: pointer;
    }
    
    #editForm {
        display: none;
    }
    
    table {
        font-family: Arial, sans-serif;
        border: 1px solid;
        border-collapse: collapse;
    }
    
    th {
        background-color: #f8f8f8;
        padding: 5px;
    }
    
    td {
        border: 1px solid;
        padding: 5px;
    }
    
  6. wwwroot/js 폴더에 이름이 지정된 site.js JavaScript 파일을 추가합니다. site.js의 내용을 다음 코드로 바꿉니다.

    const uri = 'api/todoitems';
    let todos = [];
    
    function getItems() {
      fetch(uri)
        .then(response => response.json())
        .then(data => _displayItems(data))
        .catch(error => console.error('Unable to get items.', error));
    }
    
    function addItem() {
      const addNameTextbox = document.getElementById('add-name');
    
      const item = {
        isComplete: false,
        name: addNameTextbox.value.trim()
      };
    
      fetch(uri, {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(item)
      })
        .then(response => response.json())
        .then(() => {
          getItems();
          addNameTextbox.value = '';
        })
        .catch(error => console.error('Unable to add item.', error));
    }
    
    function deleteItem(id) {
      fetch(`${uri}/${id}`, {
        method: 'DELETE'
      })
      .then(() => getItems())
      .catch(error => console.error('Unable to delete item.', error));
    }
    
    function displayEditForm(id) {
      const item = todos.find(item => item.id === id);
      
      document.getElementById('edit-name').value = item.name;
      document.getElementById('edit-id').value = item.id;
      document.getElementById('edit-isComplete').checked = item.isComplete;
      document.getElementById('editForm').style.display = 'block';
    }
    
    function updateItem() {
      const itemId = document.getElementById('edit-id').value;
      const item = {
        id: parseInt(itemId, 10),
        isComplete: document.getElementById('edit-isComplete').checked,
        name: document.getElementById('edit-name').value.trim()
      };
    
      fetch(`${uri}/${itemId}`, {
        method: 'PUT',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(item)
      })
      .then(() => getItems())
      .catch(error => console.error('Unable to update item.', error));
    
      closeInput();
    
      return false;
    }
    
    function closeInput() {
      document.getElementById('editForm').style.display = 'none';
    }
    
    function _displayCount(itemCount) {
      const name = (itemCount === 1) ? 'to-do' : 'to-dos';
    
      document.getElementById('counter').innerText = `${itemCount} ${name}`;
    }
    
    function _displayItems(data) {
      const tBody = document.getElementById('todos');
      tBody.innerHTML = '';
    
      _displayCount(data.length);
    
      const button = document.createElement('button');
    
      data.forEach(item => {
        let isCompleteCheckbox = document.createElement('input');
        isCompleteCheckbox.type = 'checkbox';
        isCompleteCheckbox.disabled = true;
        isCompleteCheckbox.checked = item.isComplete;
    
        let editButton = button.cloneNode(false);
        editButton.innerText = 'Edit';
        editButton.setAttribute('onclick', `displayEditForm(${item.id})`);
    
        let deleteButton = button.cloneNode(false);
        deleteButton.innerText = 'Delete';
        deleteButton.setAttribute('onclick', `deleteItem(${item.id})`);
    
        let tr = tBody.insertRow();
        
        let td1 = tr.insertCell(0);
        td1.appendChild(isCompleteCheckbox);
    
        let td2 = tr.insertCell(1);
        let textNode = document.createTextNode(item.name);
        td2.appendChild(textNode);
    
        let td3 = tr.insertCell(2);
        td3.appendChild(editButton);
    
        let td4 = tr.insertCell(3);
        td4.appendChild(deleteButton);
      });
    
      todos = data;
    }
    

HTML 페이지를 로컬에서 테스트하려면 ASP.NET Core 프로젝트의 시작 설정을 변경해야 할 수 있습니다.

  1. Properties\launchSettings.json을 엽니다.
  2. launchUrl 속성을 제거하여 앱이 index.html 프로젝트의 기본 파일에서 열리도록 합니다.

이 샘플은 웹 API의 CRUD 메서드를 모두 호출합니다. 웹 API 요청에 대한 설명은 다음과 같습니다.

할 일 항목의 목록 가져오기

다음 코드에서 HTTP GET 요청은 api/todoitems 경로로 전송됩니다.

fetch(uri)
  .then(response => response.json())
  .then(data => _displayItems(data))
  .catch(error => console.error('Unable to get items.', error));

웹 API가 성공한 상태 코드를 반환하면 _displayItems 함수가 호출됩니다. _displayItems에서 허용하는 배열 매개 변수의 각 할 일 항목은 편집삭제 단추가 포함된 테이블로 추가됩니다. 웹 API 요청이 실패하는 경우 브라우저의 콘솔에 오류가 기록됩니다.

할 일 항목 추가

다음 코드에서:

  • item 변수는 할 일 항목의 개체 리터럴 표현을 생성하기 위해 선언됩니다.
  • Fetch 요청은 다음 옵션으로 구성됩니다.
    • method- POST HTTP 작업 동사를 지정합니다.
    • body - 요청 본문의 JSON 표현을 지정합니다. JSON은 item에 저장된 개체 리터럴을 JSON.stringify 함수로 전달하여 생성됩니다.
    • headers - AcceptContent-Type HTTP 요청 헤더를 지정합니다. 두 헤더 모두 application/json으로 설정되어 개별적으로 수신 및 전송되는 미디어 유형을 지정합니다.
  • HTTP POST 요청은 api/todoitems 경로로 전송됩니다.
function addItem() {
  const addNameTextbox = document.getElementById('add-name');

  const item = {
    isComplete: false,
    name: addNameTextbox.value.trim()
  };

  fetch(uri, {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(item)
  })
    .then(response => response.json())
    .then(() => {
      getItems();
      addNameTextbox.value = '';
    })
    .catch(error => console.error('Unable to add item.', error));
}

웹 API가 성공적인 상태 코드를 반환하면 getItems 함수가 호출되어 HTML 테이블을 업데이트합니다. 웹 API 요청이 실패하는 경우 브라우저의 콘솔에 오류가 기록됩니다.

할 일 항목 업데이트

할 일 항목 업데이트는 항목 추가와 비슷하지만 크게 두 가지에서 차이를 보입니다.

  • 경로는 업데이트할 항목의 고유 식별자를 접미사로 가집니다. 예를 들면 api/todoitems/1과 같습니다.
  • HTTP 작업 동사는 method 옵션으로 표시되는 바와 같이 PUT입니다.
fetch(`${uri}/${itemId}`, {
  method: 'PUT',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(item)
})
.then(() => getItems())
.catch(error => console.error('Unable to update item.', error));

할 일 항목 삭제

할 일 항목을 삭제하려면 요청의 method 옵션을 DELETE로 설정하고 URL에서 항목의 고유 식별자를 지정합니다.

fetch(`${uri}/${id}`, {
  method: 'DELETE'
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));

웹 API 도움말 페이지를 생성하는 방법을 알아보려면 다음 자습서로 계속 진행합니다.

이 자습서에서는 Fetch API를 사용하여 JavaScript로 ASP.NET Core 웹 API를 호출하는 방법을 보여줍니다.

필수 조건

JavaScript를 사용하여 웹 API 호출

이 섹션에서는 할 일 항목의 생성과 관리를 위한 양식이 포함된 HTML 페이지를 추가하게 됩니다. 이벤트 처리기는 페이지의 요소에 연결됩니다. 이벤트 처리기에 의해 웹 API의 작업 메서드에 대한 HTTP 요청이 발생합니다. Fetch API의 fetch 함수는 각 HTTP 요청을 시작합니다.

fetch 함수는 Promise 개체를 반환하는데, 해당 개체에는 Response 개체로 나타나는 HTTP 응답이 포함됩니다. 일반적인 패턴은 Response 개체에 대해 json 함수를 호출하여 JSON 응답 본문을 추출하는 것입니다. JavaScript는 웹 API 응답의 세부 정보를 토대로 페이지를 업데이트합니다.

가장 간단한 fetch 호출에서는 경로를 나타내는 단일 매개 변수가 허용됩니다. init 개체라고 하는 두 번째 매개 변수는 선택 사항입니다. init은 HTTP 요청 구성에 사용됩니다.

  1. 정적 파일을 제공하고 기본 파일 매핑을 사용하도록 앱을 구성합니다. 다음의 강조 표시된 코드는 Startup.csConfigure 메서드에서 필요합니다.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseDefaultFiles();
        app.UseStaticFiles();
    
        app.UseHttpsRedirection();
    
        app.UseRouting();
    
        app.UseAuthorization();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
    
  2. 프로젝트 루트에서 wwwroot 폴더를 만듭니다.

  3. wwwroot 폴더 안에 css 폴더를 만듭니다.

  4. wwwroot 폴더 안에 js 폴더를 만듭니다.

  5. wwwroot 폴더에 명명된 index.html HTML 파일을 추가합니다. index.html의 콘텐츠를 다음 태그로 바꿉니다.

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>To-do CRUD</title>
        <link rel="stylesheet" href="css/site.css" />
    </head>
    <body>
        <h1>To-do CRUD</h1>
        <h3>Add</h3>
        <form action="javascript:void(0);" method="POST" onsubmit="addItem()">
            <input type="text" id="add-name" placeholder="New to-do">
            <input type="submit" value="Add">
        </form>
    
        <div id="editForm">
            <h3>Edit</h3>
            <form action="javascript:void(0);" onsubmit="updateItem()">
                <input type="hidden" id="edit-id">
                <input type="checkbox" id="edit-isComplete">
                <input type="text" id="edit-name">
                <input type="submit" value="Save">
                <a onclick="closeInput()" aria-label="Close">&#10006;</a>
            </form>
        </div>
    
        <p id="counter"></p>
    
        <table>
            <tr>
                <th>Is Complete?</th>
                <th>Name</th>
                <th></th>
                <th></th>
            </tr>
            <tbody id="todos"></tbody>
        </table>
    
        <script src="js/site.js" asp-append-version="true"></script>
        <script type="text/javascript">
            getItems();
        </script>
    </body>
    </html>
    
  6. wwwroot/css 폴더에 명명된 site.cssCSS 파일을 추가합니다 . 내용을 다음 스타일로 바꿉니다 site.css .

    input[type='submit'], button, [aria-label] {
        cursor: pointer;
    }
    
    #editForm {
        display: none;
    }
    
    table {
        font-family: Arial, sans-serif;
        border: 1px solid;
        border-collapse: collapse;
    }
    
    th {
        background-color: #f8f8f8;
        padding: 5px;
    }
    
    td {
        border: 1px solid;
        padding: 5px;
    }
    
  7. wwwroot/js 폴더에 이름이 지정된 site.js JavaScript 파일을 추가합니다. site.js의 내용을 다음 코드로 바꿉니다.

    const uri = 'api/todoitems';
    let todos = [];
    
    function getItems() {
      fetch(uri)
        .then(response => response.json())
        .then(data => _displayItems(data))
        .catch(error => console.error('Unable to get items.', error));
    }
    
    function addItem() {
      const addNameTextbox = document.getElementById('add-name');
    
      const item = {
        isComplete: false,
        name: addNameTextbox.value.trim()
      };
    
      fetch(uri, {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(item)
      })
        .then(response => response.json())
        .then(() => {
          getItems();
          addNameTextbox.value = '';
        })
        .catch(error => console.error('Unable to add item.', error));
    }
    
    function deleteItem(id) {
      fetch(`${uri}/${id}`, {
        method: 'DELETE'
      })
      .then(() => getItems())
      .catch(error => console.error('Unable to delete item.', error));
    }
    
    function displayEditForm(id) {
      const item = todos.find(item => item.id === id);
      
      document.getElementById('edit-name').value = item.name;
      document.getElementById('edit-id').value = item.id;
      document.getElementById('edit-isComplete').checked = item.isComplete;
      document.getElementById('editForm').style.display = 'block';
    }
    
    function updateItem() {
      const itemId = document.getElementById('edit-id').value;
      const item = {
        id: parseInt(itemId, 10),
        isComplete: document.getElementById('edit-isComplete').checked,
        name: document.getElementById('edit-name').value.trim()
      };
    
      fetch(`${uri}/${itemId}`, {
        method: 'PUT',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(item)
      })
      .then(() => getItems())
      .catch(error => console.error('Unable to update item.', error));
    
      closeInput();
    
      return false;
    }
    
    function closeInput() {
      document.getElementById('editForm').style.display = 'none';
    }
    
    function _displayCount(itemCount) {
      const name = (itemCount === 1) ? 'to-do' : 'to-dos';
    
      document.getElementById('counter').innerText = `${itemCount} ${name}`;
    }
    
    function _displayItems(data) {
      const tBody = document.getElementById('todos');
      tBody.innerHTML = '';
    
      _displayCount(data.length);
    
      const button = document.createElement('button');
    
      data.forEach(item => {
        let isCompleteCheckbox = document.createElement('input');
        isCompleteCheckbox.type = 'checkbox';
        isCompleteCheckbox.disabled = true;
        isCompleteCheckbox.checked = item.isComplete;
    
        let editButton = button.cloneNode(false);
        editButton.innerText = 'Edit';
        editButton.setAttribute('onclick', `displayEditForm(${item.id})`);
    
        let deleteButton = button.cloneNode(false);
        deleteButton.innerText = 'Delete';
        deleteButton.setAttribute('onclick', `deleteItem(${item.id})`);
    
        let tr = tBody.insertRow();
        
        let td1 = tr.insertCell(0);
        td1.appendChild(isCompleteCheckbox);
    
        let td2 = tr.insertCell(1);
        let textNode = document.createTextNode(item.name);
        td2.appendChild(textNode);
    
        let td3 = tr.insertCell(2);
        td3.appendChild(editButton);
    
        let td4 = tr.insertCell(3);
        td4.appendChild(deleteButton);
      });
    
      todos = data;
    }
    

HTML 페이지를 로컬에서 테스트하려면 ASP.NET Core 프로젝트의 시작 설정을 변경해야 할 수 있습니다.

  1. Properties\launchSettings.json을 엽니다.
  2. launchUrl 속성을 제거하여 앱이 index.html 프로젝트의 기본 파일에서 열리도록 합니다.

이 샘플은 웹 API의 CRUD 메서드를 모두 호출합니다. 웹 API 요청에 대한 설명은 다음과 같습니다.

할 일 항목의 목록 가져오기

다음 코드에서 HTTP GET 요청은 api/todoitems 경로로 전송됩니다.

fetch(uri)
  .then(response => response.json())
  .then(data => _displayItems(data))
  .catch(error => console.error('Unable to get items.', error));

웹 API가 성공한 상태 코드를 반환하면 _displayItems 함수가 호출됩니다. _displayItems에서 허용하는 배열 매개 변수의 각 할 일 항목은 편집삭제 단추가 포함된 테이블로 추가됩니다. 웹 API 요청이 실패하는 경우 브라우저의 콘솔에 오류가 기록됩니다.

할 일 항목 추가

다음 코드에서:

  • item 변수는 할 일 항목의 개체 리터럴 표현을 생성하기 위해 선언됩니다.
  • Fetch 요청은 다음 옵션으로 구성됩니다.
    • method- POST HTTP 작업 동사를 지정합니다.
    • body - 요청 본문의 JSON 표현을 지정합니다. JSON은 item에 저장된 개체 리터럴을 JSON.stringify 함수로 전달하여 생성됩니다.
    • headers - AcceptContent-Type HTTP 요청 헤더를 지정합니다. 두 헤더 모두 application/json으로 설정되어 개별적으로 수신 및 전송되는 미디어 유형을 지정합니다.
  • HTTP POST 요청은 api/todoitems 경로로 전송됩니다.
function addItem() {
  const addNameTextbox = document.getElementById('add-name');

  const item = {
    isComplete: false,
    name: addNameTextbox.value.trim()
  };

  fetch(uri, {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(item)
  })
    .then(response => response.json())
    .then(() => {
      getItems();
      addNameTextbox.value = '';
    })
    .catch(error => console.error('Unable to add item.', error));
}

웹 API가 성공적인 상태 코드를 반환하면 getItems 함수가 호출되어 HTML 테이블을 업데이트합니다. 웹 API 요청이 실패하는 경우 브라우저의 콘솔에 오류가 기록됩니다.

할 일 항목 업데이트

할 일 항목 업데이트는 항목 추가와 비슷하지만 크게 두 가지에서 차이를 보입니다.

  • 경로는 업데이트할 항목의 고유 식별자를 접미사로 가집니다. 예를 들면 api/todoitems/1과 같습니다.
  • HTTP 작업 동사는 method 옵션으로 표시되는 바와 같이 PUT입니다.
fetch(`${uri}/${itemId}`, {
  method: 'PUT',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(item)
})
.then(() => getItems())
.catch(error => console.error('Unable to update item.', error));

할 일 항목 삭제

할 일 항목을 삭제하려면 요청의 method 옵션을 DELETE로 설정하고 URL에서 항목의 고유 식별자를 지정합니다.

fetch(`${uri}/${id}`, {
  method: 'DELETE'
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));

웹 API 도움말 페이지를 생성하는 방법을 알아보려면 다음 자습서로 계속 진행합니다.

이 자습서에서는 Fetch API를 사용하여 JavaScript로 ASP.NET Core 웹 API를 호출하는 방법을 보여줍니다.

필수 조건

JavaScript를 사용하여 웹 API 호출

이 섹션에서는 할 일 항목의 생성과 관리를 위한 양식이 포함된 HTML 페이지를 추가하게 됩니다. 이벤트 처리기는 페이지의 요소에 연결됩니다. 이벤트 처리기에 의해 웹 API의 작업 메서드에 대한 HTTP 요청이 발생합니다. Fetch API의 fetch 함수는 각 HTTP 요청을 시작합니다.

fetch 함수는 Promise 개체를 반환하는데, 해당 개체에는 Response 개체로 나타나는 HTTP 응답이 포함됩니다. 일반적인 패턴은 Response 개체에 대해 json 함수를 호출하여 JSON 응답 본문을 추출하는 것입니다. JavaScript는 웹 API 응답의 세부 정보를 토대로 페이지를 업데이트합니다.

가장 간단한 fetch 호출에서는 경로를 나타내는 단일 매개 변수가 허용됩니다. init 개체라고 하는 두 번째 매개 변수는 선택 사항입니다. init은 HTTP 요청 구성에 사용됩니다.

  1. 정적 파일을 제공하고 기본 파일 매핑을 사용하도록 앱을 구성합니다. 다음 강조 표시된 코드는 다음에서 필요합니다.Program.cs
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));

var app = builder.Build();

if (builder.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseDefaultFiles();
app.UseStaticFiles();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();
  1. 프로젝트 루트에서 wwwroot 폴더를 만듭니다.

  2. wwwroot 폴더 안에 css 폴더를 만듭니다.

  3. wwwroot 폴더 안에 js 폴더를 만듭니다.

  4. wwwroot 폴더에 명명된 index.html HTML 파일을 추가합니다. index.html의 콘텐츠를 다음 태그로 바꿉니다.

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>To-do CRUD</title>
        <link rel="stylesheet" href="css/site.css" />
    </head>
    <body>
        <h1>To-do CRUD</h1>
        <h3>Add</h3>
        <form action="javascript:void(0);" method="POST" onsubmit="addItem()">
            <input type="text" id="add-name" placeholder="New to-do">
            <input type="submit" value="Add">
        </form>
    
        <div id="editForm">
            <h3>Edit</h3>
            <form action="javascript:void(0);" onsubmit="updateItem()">
                <input type="hidden" id="edit-id">
                <input type="checkbox" id="edit-isComplete">
                <input type="text" id="edit-name">
                <input type="submit" value="Save">
                <a onclick="closeInput()" aria-label="Close">&#10006;</a>
            </form>
        </div>
    
        <p id="counter"></p>
    
        <table>
            <tr>
                <th>Is Complete?</th>
                <th>Name</th>
                <th></th>
                <th></th>
            </tr>
            <tbody id="todos"></tbody>
        </table>
    
        <script src="js/site.js" asp-append-version="true"></script>
        <script type="text/javascript">
            getItems();
        </script>
    </body>
    </html>
    
  5. wwwroot/css 폴더에 명명된 site.cssCSS 파일을 추가합니다 . 내용을 다음 스타일로 바꿉니다 site.css .

    input[type='submit'], button, [aria-label] {
        cursor: pointer;
    }
    
    #editForm {
        display: none;
    }
    
    table {
        font-family: Arial, sans-serif;
        border: 1px solid;
        border-collapse: collapse;
    }
    
    th {
        background-color: #f8f8f8;
        padding: 5px;
    }
    
    td {
        border: 1px solid;
        padding: 5px;
    }
    
  6. wwwroot/js 폴더에 이름이 지정된 site.js JavaScript 파일을 추가합니다. site.js의 내용을 다음 코드로 바꿉니다.

    const uri = 'api/todoitems';
    let todos = [];
    
    function getItems() {
      fetch(uri)
        .then(response => response.json())
        .then(data => _displayItems(data))
        .catch(error => console.error('Unable to get items.', error));
    }
    
    function addItem() {
      const addNameTextbox = document.getElementById('add-name');
    
      const item = {
        isComplete: false,
        name: addNameTextbox.value.trim()
      };
    
      fetch(uri, {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(item)
      })
        .then(response => response.json())
        .then(() => {
          getItems();
          addNameTextbox.value = '';
        })
        .catch(error => console.error('Unable to add item.', error));
    }
    
    function deleteItem(id) {
      fetch(`${uri}/${id}`, {
        method: 'DELETE'
      })
      .then(() => getItems())
      .catch(error => console.error('Unable to delete item.', error));
    }
    
    function displayEditForm(id) {
      const item = todos.find(item => item.id === id);
      
      document.getElementById('edit-name').value = item.name;
      document.getElementById('edit-id').value = item.id;
      document.getElementById('edit-isComplete').checked = item.isComplete;
      document.getElementById('editForm').style.display = 'block';
    }
    
    function updateItem() {
      const itemId = document.getElementById('edit-id').value;
      const item = {
        id: parseInt(itemId, 10),
        isComplete: document.getElementById('edit-isComplete').checked,
        name: document.getElementById('edit-name').value.trim()
      };
    
      fetch(`${uri}/${itemId}`, {
        method: 'PUT',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(item)
      })
      .then(() => getItems())
      .catch(error => console.error('Unable to update item.', error));
    
      closeInput();
    
      return false;
    }
    
    function closeInput() {
      document.getElementById('editForm').style.display = 'none';
    }
    
    function _displayCount(itemCount) {
      const name = (itemCount === 1) ? 'to-do' : 'to-dos';
    
      document.getElementById('counter').innerText = `${itemCount} ${name}`;
    }
    
    function _displayItems(data) {
      const tBody = document.getElementById('todos');
      tBody.innerHTML = '';
    
      _displayCount(data.length);
    
      const button = document.createElement('button');
    
      data.forEach(item => {
        let isCompleteCheckbox = document.createElement('input');
        isCompleteCheckbox.type = 'checkbox';
        isCompleteCheckbox.disabled = true;
        isCompleteCheckbox.checked = item.isComplete;
    
        let editButton = button.cloneNode(false);
        editButton.innerText = 'Edit';
        editButton.setAttribute('onclick', `displayEditForm(${item.id})`);
    
        let deleteButton = button.cloneNode(false);
        deleteButton.innerText = 'Delete';
        deleteButton.setAttribute('onclick', `deleteItem(${item.id})`);
    
        let tr = tBody.insertRow();
        
        let td1 = tr.insertCell(0);
        td1.appendChild(isCompleteCheckbox);
    
        let td2 = tr.insertCell(1);
        let textNode = document.createTextNode(item.name);
        td2.appendChild(textNode);
    
        let td3 = tr.insertCell(2);
        td3.appendChild(editButton);
    
        let td4 = tr.insertCell(3);
        td4.appendChild(deleteButton);
      });
    
      todos = data;
    }
    

HTML 페이지를 로컬에서 테스트하려면 ASP.NET Core 프로젝트의 시작 설정을 변경해야 할 수 있습니다.

  1. Properties\launchSettings.json을 엽니다.
  2. launchUrl 속성을 제거하여 앱이 index.html 프로젝트의 기본 파일에서 열리도록 합니다.

이 샘플은 웹 API의 CRUD 메서드를 모두 호출합니다. 웹 API 요청에 대한 설명은 다음과 같습니다.

할 일 항목의 목록 가져오기

다음 코드에서 HTTP GET 요청은 api/todoitems 경로로 전송됩니다.

fetch(uri)
  .then(response => response.json())
  .then(data => _displayItems(data))
  .catch(error => console.error('Unable to get items.', error));

웹 API가 성공한 상태 코드를 반환하면 _displayItems 함수가 호출됩니다. _displayItems에서 허용하는 배열 매개 변수의 각 할 일 항목은 편집삭제 단추가 포함된 테이블로 추가됩니다. 웹 API 요청이 실패하는 경우 브라우저의 콘솔에 오류가 기록됩니다.

할 일 항목 추가

다음 코드에서:

  • item 변수는 할 일 항목의 개체 리터럴 표현을 생성하기 위해 선언됩니다.
  • Fetch 요청은 다음 옵션으로 구성됩니다.
    • method- POST HTTP 작업 동사를 지정합니다.
    • body - 요청 본문의 JSON 표현을 지정합니다. JSON은 item에 저장된 개체 리터럴을 JSON.stringify 함수로 전달하여 생성됩니다.
    • headers - AcceptContent-Type HTTP 요청 헤더를 지정합니다. 두 헤더 모두 application/json으로 설정되어 개별적으로 수신 및 전송되는 미디어 유형을 지정합니다.
  • HTTP POST 요청은 api/todoitems 경로로 전송됩니다.
function addItem() {
  const addNameTextbox = document.getElementById('add-name');

  const item = {
    isComplete: false,
    name: addNameTextbox.value.trim()
  };

  fetch(uri, {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(item)
  })
    .then(response => response.json())
    .then(() => {
      getItems();
      addNameTextbox.value = '';
    })
    .catch(error => console.error('Unable to add item.', error));
}

웹 API가 성공적인 상태 코드를 반환하면 getItems 함수가 호출되어 HTML 테이블을 업데이트합니다. 웹 API 요청이 실패하는 경우 브라우저의 콘솔에 오류가 기록됩니다.

할 일 항목 업데이트

할 일 항목 업데이트는 항목 추가와 비슷하지만 크게 두 가지에서 차이를 보입니다.

  • 경로는 업데이트할 항목의 고유 식별자를 접미사로 가집니다. 예를 들면 api/todoitems/1과 같습니다.
  • HTTP 작업 동사는 method 옵션으로 표시되는 바와 같이 PUT입니다.
fetch(`${uri}/${itemId}`, {
  method: 'PUT',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(item)
})
.then(() => getItems())
.catch(error => console.error('Unable to update item.', error));

할 일 항목 삭제

할 일 항목을 삭제하려면 요청의 method 옵션을 DELETE로 설정하고 URL에서 항목의 고유 식별자를 지정합니다.

fetch(`${uri}/${id}`, {
  method: 'DELETE'
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));

웹 API 도움말 페이지를 생성하는 방법을 알아보려면 다음 자습서로 계속 진행합니다.