Tutorial: chamar uma API Web do ASP.NET Core com o JavaScript

De Rick Anderson

Este tutorial mostra como chamar uma API Web do ASP.NET Core com JavaScript, usando a API Fetch.

Pré-requisitos

Chamar a API Web com o JavaScript

Nesta seção, você adicionará uma página HTML que contém formulários para criar e gerenciar itens de tarefas pendentes. Manipuladores de eventos são anexados aos elementos na página. Os manipuladores de eventos resultam em solicitações HTTP para os métodos de ação da API Web. A função fetch da API Fetch inicia cada solicitação HTTP.

A função fetch retorna um objeto Promise, que contém uma resposta HTTP representada como um objeto Response. Um padrão comum é extrair o corpo da resposta JSON invocando a função json no objeto Response. O JavaScript atualiza a página com os detalhes da resposta da API Web.

A chamada fetch mais simples aceita um parâmetro único que representa a rota. Um segundo parâmetro, conhecido como objeto init, é opcional. init é usado para configurar a solicitação HTTP.

  1. Configure o aplicativo para fornecer arquivos estáticos e habilitar o mapeamento de arquivo padrão. O código realçado a seguir é necessário em 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. Crie uma pasta wwwroot na raiz do projeto.

  2. Crie uma pasta css dentro da pasta wwwroot.

  3. Crie uma pasta js dentro da pasta wwwroot .

  4. Adicione um arquivo HTML chamado index.html à pasta wwwroot. Substitua o conteúdo de index.html pela marcação a seguir:

    <!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. Adicione um arquivo CSS chamado site.css à pasta wwwroot/css. Substitua o conteúdo de site.css pelos estilos a seguir:

    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. Adicione um arquivo JavaScript nomeado site.js para a pasta wwwroot/js . Substitua o conteúdo de site.js pelo seguinte código:

    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;
    }
    

Uma alteração nas configurações de inicialização do projeto ASP.NET Core pode ser necessária para testar a página HTML localmente:

  1. Abra Properties\launchSettings.json.
  2. Remova a propriedade launchUrl para forçar o aplicativo a abrir em index.html – o arquivo padrão do projeto.

Esta amostra chama todos os métodos CRUD da API Web. A seguir, são apresentadas explicações sobre as solicitações de API Web.

Obter uma lista de itens pendentes

No código a seguir, uma solicitação HTTP GET é enviada para a rota de api/todoitems:

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

Quando a API Web retorna um código de status bem-sucedido, a função _displayItems é invocada. Cada item de tarefas pendentes no parâmetro de matriz aceito por _displayItems é adicionado a uma tabela com os botões Editar e Excluir. Se a solicitação da API Web falhar, um erro será registrado no console do navegador.

Adicionar um item pendente

No seguinte código:

  • Uma variável item é declarada para construir uma representação literal de objeto do item de tarefas pendentes.
  • Uma solicitação Fetch é configurada com as seguintes opções:
    • method – especifica o verbo de ação HTTP POST.
    • body—especifica a representação JSON do corpo da solicitação. O JSON é produzido passando o literal de objeto armazenado em item para a função JSON.stringify.
    • headers – especifica os cabeçalhos de solicitação HTTP Accept e Content-Type. Ambos os cabeçalhos são definidos como application/json para especificar o tipo de mídia que está sendo recebido e enviado, respectivamente.
  • Uma solicitação HTTP POST é enviada para a rota 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));
}

Quando a API Web retorna um código de status de êxito, a função getItems é invocada para atualizar a tabela HTML. Se a solicitação da API Web falhar, um erro será registrado no console do navegador.

Atualizar um item pendente

A atualização de um item de tarefas pendentes é semelhante à adição de um; no entanto, há duas diferenças significativas:

  • A rota recebe como sufixo o identificador único do item a ser atualizado. Por exemplo, api/todoitems/1.
  • O verbo de ação HTTP é PUT, conforme indicado pela opção method.
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));

Excluir um item pendente

Para excluir um item de tarefas pendentes, defina a opção method da solicitação como DELETE e especifique o identificador exclusivo do item na URL.

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

Avance para o próximo tutorial para saber como gerar páginas de ajuda da API Web:

Este tutorial mostra como chamar uma API Web do ASP.NET Core com JavaScript, usando a API Fetch.

Pré-requisitos

Chamar a API Web com o JavaScript

Nesta seção, você adicionará uma página HTML que contém formulários para criar e gerenciar itens de tarefas pendentes. Manipuladores de eventos são anexados aos elementos na página. Os manipuladores de eventos resultam em solicitações HTTP para os métodos de ação da API Web. A função fetch da API Fetch inicia cada solicitação HTTP.

A função fetch retorna um objeto Promise, que contém uma resposta HTTP representada como um objeto Response. Um padrão comum é extrair o corpo da resposta JSON invocando a função json no objeto Response. O JavaScript atualiza a página com os detalhes da resposta da API Web.

A chamada fetch mais simples aceita um parâmetro único que representa a rota. Um segundo parâmetro, conhecido como objeto init, é opcional. init é usado para configurar a solicitação HTTP.

  1. Configure o aplicativo para fornecer arquivos estáticos e habilitar o mapeamento de arquivo padrão. O seguinte código destacado é necessário no método Configure de Startup.cs:

    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. Crie uma pasta wwwroot na raiz do projeto.

  3. Crie uma pasta css dentro da pasta wwwroot.

  4. Crie uma pasta js dentro da pasta wwwroot .

  5. Adicione um arquivo HTML chamado index.html à pasta wwwroot. Substitua o conteúdo de index.html pela marcação a seguir:

    <!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. Adicione um arquivo CSS chamado site.css à pasta wwwroot/css. Substitua o conteúdo de site.css pelos estilos a seguir:

    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. Adicione um arquivo JavaScript nomeado site.js para a pasta wwwroot/js . Substitua o conteúdo de site.js pelo seguinte código:

    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;
    }
    

Uma alteração nas configurações de inicialização do projeto ASP.NET Core pode ser necessária para testar a página HTML localmente:

  1. Abra Properties\launchSettings.json.
  2. Remova a propriedade launchUrl para forçar o aplicativo a abrir em index.html – o arquivo padrão do projeto.

Esta amostra chama todos os métodos CRUD da API Web. A seguir, são apresentadas explicações sobre as solicitações de API Web.

Obter uma lista de itens pendentes

No código a seguir, uma solicitação HTTP GET é enviada para a rota de api/todoitems:

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

Quando a API Web retorna um código de status bem-sucedido, a função _displayItems é invocada. Cada item de tarefas pendentes no parâmetro de matriz aceito por _displayItems é adicionado a uma tabela com os botões Editar e Excluir. Se a solicitação da API Web falhar, um erro será registrado no console do navegador.

Adicionar um item pendente

No seguinte código:

  • Uma variável item é declarada para construir uma representação literal de objeto do item de tarefas pendentes.
  • Uma solicitação Fetch é configurada com as seguintes opções:
    • method – especifica o verbo de ação HTTP POST.
    • body—especifica a representação JSON do corpo da solicitação. O JSON é produzido passando o literal de objeto armazenado em item para a função JSON.stringify.
    • headers – especifica os cabeçalhos de solicitação HTTP Accept e Content-Type. Ambos os cabeçalhos são definidos como application/json para especificar o tipo de mídia que está sendo recebido e enviado, respectivamente.
  • Uma solicitação HTTP POST é enviada para a rota 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));
}

Quando a API Web retorna um código de status de êxito, a função getItems é invocada para atualizar a tabela HTML. Se a solicitação da API Web falhar, um erro será registrado no console do navegador.

Atualizar um item pendente

A atualização de um item de tarefas pendentes é semelhante à adição de um; no entanto, há duas diferenças significativas:

  • A rota recebe como sufixo o identificador único do item a ser atualizado. Por exemplo, api/todoitems/1.
  • O verbo de ação HTTP é PUT, conforme indicado pela opção method.
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));

Excluir um item pendente

Para excluir um item de tarefas pendentes, defina a opção method da solicitação como DELETE e especifique o identificador exclusivo do item na URL.

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

Avance para o próximo tutorial para saber como gerar páginas de ajuda da API Web:

Este tutorial mostra como chamar uma API Web do ASP.NET Core com JavaScript, usando a API Fetch.

Pré-requisitos

Chamar a API Web com o JavaScript

Nesta seção, você adicionará uma página HTML que contém formulários para criar e gerenciar itens de tarefas pendentes. Manipuladores de eventos são anexados aos elementos na página. Os manipuladores de eventos resultam em solicitações HTTP para os métodos de ação da API Web. A função fetch da API Fetch inicia cada solicitação HTTP.

A função fetch retorna um objeto Promise, que contém uma resposta HTTP representada como um objeto Response. Um padrão comum é extrair o corpo da resposta JSON invocando a função json no objeto Response. O JavaScript atualiza a página com os detalhes da resposta da API Web.

A chamada fetch mais simples aceita um parâmetro único que representa a rota. Um segundo parâmetro, conhecido como objeto init, é opcional. init é usado para configurar a solicitação HTTP.

  1. Configure o aplicativo para fornecer arquivos estáticos e habilitar o mapeamento de arquivo padrão. O código realçado a seguir é necessário em 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. Crie uma pasta wwwroot na raiz do projeto.

  2. Crie uma pasta css dentro da pasta wwwroot.

  3. Crie uma pasta js dentro da pasta wwwroot .

  4. Adicione um arquivo HTML chamado index.html à pasta wwwroot. Substitua o conteúdo de index.html pela marcação a seguir:

    <!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. Adicione um arquivo CSS chamado site.css à pasta wwwroot/css. Substitua o conteúdo de site.css pelos estilos a seguir:

    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. Adicione um arquivo JavaScript nomeado site.js para a pasta wwwroot/js . Substitua o conteúdo de site.js pelo seguinte código:

    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;
    }
    

Uma alteração nas configurações de inicialização do projeto ASP.NET Core pode ser necessária para testar a página HTML localmente:

  1. Abra Properties\launchSettings.json.
  2. Remova a propriedade launchUrl para forçar o aplicativo a abrir em index.html – o arquivo padrão do projeto.

Esta amostra chama todos os métodos CRUD da API Web. A seguir, são apresentadas explicações sobre as solicitações de API Web.

Obter uma lista de itens pendentes

No código a seguir, uma solicitação HTTP GET é enviada para a rota de api/todoitems:

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

Quando a API Web retorna um código de status bem-sucedido, a função _displayItems é invocada. Cada item de tarefas pendentes no parâmetro de matriz aceito por _displayItems é adicionado a uma tabela com os botões Editar e Excluir. Se a solicitação da API Web falhar, um erro será registrado no console do navegador.

Adicionar um item pendente

No seguinte código:

  • Uma variável item é declarada para construir uma representação literal de objeto do item de tarefas pendentes.
  • Uma solicitação Fetch é configurada com as seguintes opções:
    • method – especifica o verbo de ação HTTP POST.
    • body—especifica a representação JSON do corpo da solicitação. O JSON é produzido passando o literal de objeto armazenado em item para a função JSON.stringify.
    • headers – especifica os cabeçalhos de solicitação HTTP Accept e Content-Type. Ambos os cabeçalhos são definidos como application/json para especificar o tipo de mídia que está sendo recebido e enviado, respectivamente.
  • Uma solicitação HTTP POST é enviada para a rota 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));
}

Quando a API Web retorna um código de status de êxito, a função getItems é invocada para atualizar a tabela HTML. Se a solicitação da API Web falhar, um erro será registrado no console do navegador.

Atualizar um item pendente

A atualização de um item de tarefas pendentes é semelhante à adição de um; no entanto, há duas diferenças significativas:

  • A rota recebe como sufixo o identificador único do item a ser atualizado. Por exemplo, api/todoitems/1.
  • O verbo de ação HTTP é PUT, conforme indicado pela opção method.
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));

Excluir um item pendente

Para excluir um item de tarefas pendentes, defina a opção method da solicitação como DELETE e especifique o identificador exclusivo do item na URL.

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

Avance para o próximo tutorial para saber como gerar páginas de ajuda da API Web: