Tutorial: criar uma API Web com o ASP.NET CoreTutorial: Create a web API with ASP.NET Core

Por Rick Anderson, Kirk Larkine Mike WassonBy Rick Anderson, Kirk Larkin, and Mike Wasson

Este tutorial ensina os conceitos básicos da criação de uma API Web com o ASP.NET Core.This tutorial teaches the basics of building a web API with ASP.NET Core.

Neste tutorial, você aprenderá como:In this tutorial, you learn how to:

  • Criar um projeto de API Web.Create a web API project.
  • Adicione uma classe de modelo e um contexto de banco de dados.Add a model class and a database context.
  • Faça scaffold de um controlador com métodos CRUD.Scaffold a controller with CRUD methods.
  • Configure o roteamento, os caminhos de URL e os valores retornados.Configure routing, URL paths, and return values.
  • Chamar a API Web com o Postman.Call the web API with Postman.

No final, você terá uma API Web que pode gerenciar itens de "tarefas pendentes" armazenados em um banco de dados.At the end, you have a web API that can manage "to-do" items stored in a database.

Visão geralOverview

Este tutorial cria a seguinte API:This tutorial creates the following API:

APIAPI DescriçãoDescription Corpo da solicitaçãoRequest body Corpo da respostaResponse body
GET /api/TodoItems Obter todos os itens de tarefas pendentesGet all to-do items NenhumNone Matriz de itens de tarefas pendentesArray of to-do items
GET /api/TodoItems/{id} Obter um item por IDGet an item by ID NenhumNone Item de tarefas pendentesTo-do item
POST /api/TodoItems Adicionar um novo itemAdd a new item Item de tarefas pendentesTo-do item Item de tarefas pendentesTo-do item
PUT /api/TodoItems/{id} Atualizar um item   existenteUpdate an existing item   Item de tarefas pendentesTo-do item NenhumNone
DELETE /api/TodoItems/{id}    DELETE /api/TodoItems/{id}     Excluir um item   Delete an item     NenhumNone NenhumNone

O diagrama a seguir mostra o design do aplicativo.The following diagram shows the design of the app.

O cliente é representado por uma caixa à esquerda.

Pré-requisitosPrerequisites

Criar um projeto WebCreate a web project

  • No menu arquivo , selecione novo > projeto.From the File menu, select New > Project.
  • Selecione o modelo Aplicativo Web ASP.NET Core e clique em Próximo.Select the ASP.NET Core Web Application template and click Next.
  • Nomeie o projeto como TodoApi e clique em Criar.Name the project TodoApi and click Create.
  • Na caixa de diálogo criar um novo ASP.NET Core aplicativo Web , confirme se o .net Core e ASP.NET Core 5,0 estão selecionados.In the Create a new ASP.NET Core Web Application dialog, confirm that .NET Core and ASP.NET Core 5.0 are selected. Selecione o modelo API e clique em Criar.Select the API template and click Create.

Caixa de diálogo Novo projeto do VS

Testar o projetoTest the project

O modelo de projeto cria uma WeatherForecast API com suporte para Swagger.The project template creates a WeatherForecast API with support for Swagger.

Pressione Ctrl + F5 para execução sem o depurador.Press Ctrl+F5 to run without the debugger.

O Visual Studio exibe a caixa de diálogo a seguir:Visual Studio displays the following dialog:

Este projeto é configurado para usar SSL.

Selecione Sim se você confia no certificado SSL do IIS Express.Select Yes if you trust the IIS Express SSL certificate.

A seguinte caixa de diálogo é exibida:The following dialog is displayed:

Caixa de diálogo de aviso de segurança

Selecione Sim se você concordar com confiar no certificado de desenvolvimento.Select Yes if you agree to trust the development certificate.

Para obter informações sobre como confiar no navegador Firefox, consulte erro de certificado do firefox SEC_ERROR_INADEQUATE_KEY_USAGE.For information on trusting the Firefox browser, see Firefox SEC_ERROR_INADEQUATE_KEY_USAGE certificate error.

O Visual Studio é iniciado:Visual Studio launches:

  • O servidor Web IIS Express.The IIS Express web server.
  • O navegador padrão e navega para https://localhost:<port>/swagger/index.html , em que <port> é um número de porta escolhido aleatoriamente.The default browser and navigates to https://localhost:<port>/swagger/index.html, where <port> is a randomly chosen port number.

A página Swagger /swagger/index.html é exibida.The Swagger page /swagger/index.html is displayed. Selecione Get > Experimente > executar.Select GET > Try it out > Execute. A página exibe:The page displays:

  • O comando de ondulação para testar a API WeatherForecast.The Curl command to test the WeatherForecast API.
  • A URL para testar a API WeatherForecast.The URL to test the WeatherForecast API.
  • O código de resposta, o corpo e os cabeçalhos.The response code, body, and headers.
  • Uma caixa de listagem suspensa com tipos de mídia e o valor e o esquema de exemplo.A drop down list box with media types and the example value and schema.

O Swagger é usado para gerar documentação útil e páginas de ajuda para APIs da Web.Swagger is used to generate useful documentation and help pages for web APIs. Este tutorial se concentra na criação de uma API da Web.This tutorial focuses on creating a web API. Para obter mais informações sobre o Swagger, consulte Documentação da API Web do ASP.NET Core com o Swagger/OpenAPI .For more information on Swagger, see Documentação da API Web do ASP.NET Core com o Swagger/OpenAPI.

Copie e cole a URL de solicitação no navegador: https://localhost:<port>/WeatherForecastCopy and paste the Request URL in the browser: https://localhost:<port>/WeatherForecast

Um JSON semelhante ao seguinte será retornado:JSON similar to the following is returned:

[
    {
        "date": "2019-07-16T19:04:05.7257911-06:00",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2019-07-17T19:04:05.7258461-06:00",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2019-07-18T19:04:05.7258467-06:00",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2019-07-19T19:04:05.7258471-06:00",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2019-07-20T19:04:05.7258474-06:00",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

Atualizar o launchUrlUpdate the launchUrl

No Properties\launchSettings.jsem, atualize launchUrl do "swagger" para "api/TodoItems" :In Properties\launchSettings.json, update launchUrl from "swagger" to "api/TodoItems":

"launchUrl": "api/TodoItems",

Como o Swagger foi removido, a marcação anterior altera a URL que é iniciada para o método GET do controlador adicionado nas seções a seguir.Because Swagger has been removed, the preceding markup changes the URL that is launched to the GET method of the controller added in the following sections.

Adicionar uma classe de modeloAdd a model class

Um modelo é um conjunto de classes que representam os dados gerenciados pelo aplicativo.A model is a set of classes that represent the data that the app manages. O modelo para esse aplicativo é uma única classe TodoItem.The model for this app is a single TodoItem class.

  • Em Gerenciador de soluções, clique com o botão direito do mouse no projeto.In Solution Explorer, right-click the project. Selecione Adicionar > nova pasta.Select Add > New Folder. Nomeie a pasta Models .Name the folder Models.

  • Clique com o botão direito do mouse na Models pasta e selecione Adicionar > classe.Right-click the Models folder and select Add > Class. Dê à classe o nome TodoItem e selecione Adicionar.Name the class TodoItem and select Add.

  • Substitua o código do modelo pelo seguinte:Replace the template code with the following:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

A propriedade Id funciona como a chave exclusiva em um banco de dados relacional.The Id property functions as the unique key in a relational database.

As classes de modelo podem ir em qualquer lugar no projeto, mas a Models pasta é usada pela Convenção.Model classes can go anywhere in the project, but the Models folder is used by convention.

Adicionar um contexto de banco de dadosAdd a database context

O contexto de banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um modelo de dados.The database context is the main class that coordinates Entity Framework functionality for a data model. Essa classe é criada derivando-a da classe Microsoft.EntityFrameworkCore.DbContext.This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext class.

Adicionar pacotes NuGetAdd NuGet packages

  • No menu Ferramentas, selecione Gerenciador de Pacotes do NuGet > Gerenciar Pacotes do NuGet para a Solução.From the Tools menu, select NuGet Package Manager > Manage NuGet Packages for Solution.
  • Selecione a guia procurar e, em seguida, insira Microsoft.EntityFrameworkCore.InMemory na caixa de pesquisa.Select the Browse tab, and then enter Microsoft.EntityFrameworkCore.InMemory in the search box.
  • Selecione Microsoft.EntityFrameworkCore.InMemory no painel esquerdo.Select Microsoft.EntityFrameworkCore.InMemory in the left pane.
  • Selecione a caixa de seleção Projeto no painel direito e, em seguida, selecione Instalar.Select the Project check box in the right pane and then select Install.

Gerenciador de Pacotes NuGet

Adicione o contexto de banco de dados TodoContextAdd the TodoContext database context

  • Clique com o botão direito do mouse na Models pasta e selecione Adicionar > classe.Right-click the Models folder and select Add > Class. Nomeie a classe como TodoContext e clique em Adicionar.Name the class TodoContext and click Add.
  • Insira o seguinte código:Enter the following code:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models
    {
        public class TodoContext : DbContext
        {
            public TodoContext(DbContextOptions<TodoContext> options)
                : base(options)
            {
            }
    
            public DbSet<TodoItem> TodoItems { get; set; }
        }
    }
    

Registrar o contexto do banco de dadosRegister the database context

No ASP.NET Core, serviços como o contexto de BD precisam ser registrados no contêiner de DI (injeção de dependência).In ASP.NET Core, services such as the DB context must be registered with the dependency injection (DI) container. O contêiner fornece o serviço aos controladores.The container provides the service to controllers.

Atualize Startup.cs com o seguinte código:Update Startup.cs with the following code:

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
                                               opt.UseInMemoryDatabase("TodoList"));
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

O código anterior:The preceding code:

  • Remove as chamadas do Swagger.Removes the Swagger calls.
  • Remove as declarações using não utilizadas.Removes unused using declarations.
  • Adiciona o contexto de banco de dados ao contêiner de DI.Adds the database context to the DI container.
  • Especifica que o contexto de banco de dados usará um banco de dados em memória.Specifies that the database context will use an in-memory database.

Faça scaffold de um controladorScaffold a controller

  • Clique com o botão direito do mouse na pasta Controllers.Right-click the Controllers folder.

  • Selecione Adicionar > Novo item com scaffold.Select Add > New Scaffolded Item.

  • Selecione Controlador de API com ações, usando o Entity Framework e, em seguida, selecione Adicionar.Select API Controller with actions, using Entity Framework, and then select Add.

  • Na caixa de diálogo Adicionar Controlador de API com ações, usando o Entity Framework:In the Add API Controller with actions, using Entity Framework dialog:

    • Selecione TodoItem (TodoApi. Models ) na classe Model.Select TodoItem (TodoApi.Models) in the Model class.
    • Selecione TodoContext (TodoApi. Models ) na classe de contexto de dados.Select TodoContext (TodoApi.Models) in the Data context class.
    • Selecione Adicionar.Select Add.

O código gerado:The generated code:

  • Marca a classe com o [ApiController] atributo.Marks the class with the [ApiController] attribute. Esse atributo indica se o controlador responde às solicitações da API Web.This attribute indicates that the controller responds to web API requests. Para saber mais sobre comportamentos específicos habilitados pelo atributo, consulte Criar APIs Web com o ASP.NET Core.For information about specific behaviors that the attribute enables, see Criar APIs Web com o ASP.NET Core.
  • Usa a DI para injetar o contexto de banco de dados (TodoContext) no controlador.Uses DI to inject the database context (TodoContext) into the controller. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.The database context is used in each of the CRUD methods in the controller.

Os modelos de ASP.NET Core para:The ASP.NET Core templates for:

  • Os controladores com exibições incluem [action] no modelo de rota.Controllers with views include [action] in the route template.
  • Os controladores de API não incluem [action] no modelo de rota.API controllers don't include [action] in the route template.

Quando o [action] token não está no modelo de rota, o nome da ação é excluído da rota.When the [action] token isn't in the route template, the action name is excluded from the route. Ou seja, o nome do método associado da ação não é usado na rota correspondente.That is, the action's associated method name isn't used in the matching route.

Atualizar o método de criação de PostTodoItemUpdate the PostTodoItem create method

Atualize a instrução return no PostTodoItem para usar o operador nameof :Update the return statement in the PostTodoItem to use the nameof operator:

// POST: api/TodoItems
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

O código anterior é um método HTTP POST, conforme indicado pelo [HttpPost] atributo.The preceding code is an HTTP POST method, as indicated by the [HttpPost] attribute. O método obtém o valor do item pendente no corpo da solicitação HTTP.The method gets the value of the to-do item from the body of the HTTP request.

Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].For more information, see Attribute routing with Http[Verb] attributes.

O método CreatedAtAction:The CreatedAtAction method:

  • Retorna um código de status HTTP 201 se for bem-sucedido.Returns an HTTP 201 status code if successful. HTTP 201 é a resposta padrão para um método HTTP POST que cria um novo recurso no servidor.HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.
  • Adiciona um cabeçalho de Local à resposta.Adds a Location header to the response. O cabeçalho Location especifica o URI do item de tarefas pendentes recém-criado.The Location header specifies the URI of the newly created to-do item. Para obter mais informações, confira 10.2.2 201 Criado.For more information, see 10.2.2 201 Created.
  • Faz referência à ação GetTodoItem para criar o URI de Location do cabeçalho.References the GetTodoItem action to create the Location header's URI. A palavra-chave nameof do C# é usada para evitar o hard-coding do nome da ação, na chamada CreatedAtAction.The C# nameof keyword is used to avoid hard-coding the action name in the CreatedAtAction call.

Instale o PostmanInstall Postman

Este tutorial usa o Postman para testar a API Web.This tutorial uses Postman to test the web API.

  • Instalar o postmasterInstall Postman
  • Inicie o aplicativo Web.Start the web app.
  • Inicie o Postman.Start Postman.
  • Desabilite a Verificação do certificado SSLDisable SSL certificate verification
    • Em Arquivo > Configurações (guia Geral), desabilite Verificação de certificado SSL.From File > Settings (General tab), disable SSL certificate verification.

      Aviso

      Habilite novamente a verificação do certificado SSL depois de testar o controlador.Re-enable SSL certificate verification after testing the controller.

Teste o PostTodoItem com o PostmanTest PostTodoItem with Postman

  • Crie uma solicitação.Create a new request.

  • Defina o método HTTP como POST.Set the HTTP method to POST.

  • Defina o URI como https://localhost:<port>/api/TodoItems .Set the URI to https://localhost:<port>/api/TodoItems. Por exemplo, https://localhost:5001/api/TodoItems.For example, https://localhost:5001/api/TodoItems.

  • Selecione a guia Corpo.Select the Body tab.

  • Selecione o botão de opção bruto.Select the raw radio button.

  • Defina o tipo como JSON (aplicativo/json).Set the type to JSON (application/json).

  • No corpo da solicitação, insira JSON para um item pendente:In the request body enter JSON for a to-do item:

    {
      "name":"walk dog",
      "isComplete":true
    }
    
  • Selecione Enviar.Select Send.

    Postman com a solicitação Create

Testar o URI do cabeçalho de localTest the location header URI

O URI do cabeçalho do local pode ser testado no navegador.The location header URI can be tested in the browser. Copie e cole o URI do cabeçalho de local no navegador.Copy and paste the location header URI into the browser.

Para testar no postmaster:To test in Postman:

  • Selecione a guia Cabeçalhos no painel Resposta.Select the Headers tab in the Response pane.

  • Copie o valor do cabeçalho Local:Copy the Location header value:

    Guia Cabeçalhos do console do Postman

  • Defina o método HTTP como GET.Set the HTTP method to GET.

  • Defina o URI como https://localhost:<port>/api/TodoItems/1 .Set the URI to https://localhost:<port>/api/TodoItems/1. Por exemplo, https://localhost:5001/api/TodoItems/1.For example, https://localhost:5001/api/TodoItems/1.

  • Selecione Enviar.Select Send.

Examine os métodos GETExamine the GET methods

Dois pontos de extremidade GET são implementados:Two GET endpoints are implemented:

  • GET /api/TodoItems
  • GET /api/TodoItems/{id}

Teste o aplicativo chamando os dois pontos de extremidade de um navegador ou do Postman.Test the app by calling the two endpoints from a browser or Postman. Por exemplo: For example:

  • https://localhost:5001/api/TodoItems
  • https://localhost:5001/api/TodoItems/1

Uma resposta semelhante à seguinte é produzida pela chamada a GetTodoItems:A response similar to the following is produced by the call to GetTodoItems:

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]

Teste o GET com o PostmanTest Get with Postman

  • Crie uma solicitação.Create a new request.
  • Defina o método HTTP como GET.Set the HTTP method to GET.
  • Defina o URI de solicitação como https://localhost:<port>/api/TodoItems .Set the request URI to https://localhost:<port>/api/TodoItems. Por exemplo, https://localhost:5001/api/TodoItems.For example, https://localhost:5001/api/TodoItems.
  • Defina Exibição de dois painéis no Postman.Set Two pane view in Postman.
  • Selecione Enviar.Select Send.

Este aplicativo usa um banco de dados em memória.This app uses an in-memory database. Se o aplicativo for interrompido e iniciado, a solicitação GET anterior não retornará nenhum dado.If the app is stopped and started, the preceding GET request will not return any data. Se nenhum dado for retornado, execute POST de dados no aplicativo.If no data is returned, POST data to the app.

Roteamento e caminhos de URLRouting and URL paths

O [HttpGet] atributo denota um método que responde a uma solicitação HTTP Get.The [HttpGet] attribute denotes a method that responds to an HTTP GET request. O caminho da URL de cada método é construído da seguinte maneira:The URL path for each method is constructed as follows:

  • Comece com a cadeia de caracteres de modelo no atributo Route do controlador:Start with the template string in the controller's Route attribute:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    {
        private readonly TodoContext _context;
    
        public TodoItemsController(TodoContext context)
        {
            _context = context;
        }
    
  • Substitua [controller] pelo nome do controlador, que é o nome de classe do controlador menos o sufixo "Controlador" por convenção.Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. Para esta amostra, o nome da classe do controlador é TodoItems Controller. Portanto, o nome do controlador é "TodoItems".For this sample, the controller class name is TodoItems Controller, so the controller name is "TodoItems". O roteamento do ASP.NET Core não diferencia maiúsculas de minúsculas.ASP.NET Core routing is case insensitive.

  • Se o atributo [HttpGet] tiver um modelo de rota (por exemplo, [HttpGet("products")]), acrescente isso ao caminho.If the [HttpGet] attribute has a route template (for example, [HttpGet("products")]), append that to the path. Esta amostra não usa um modelo.This sample doesn't use a template. Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].For more information, see Attribute routing with Http[Verb] attributes.

No método GetTodoItem a seguir, "{id}" é uma variável de espaço reservado para o identificador exclusivo do item pendente.In the following GetTodoItem method, "{id}" is a placeholder variable for the unique identifier of the to-do item. Quando GetTodoItem é invocado, o valor de "{id}" na URL é fornecido para o método em seu id parâmetro.When GetTodoItem is invoked, the value of "{id}" in the URL is provided to the method in its id parameter.

// GET: api/TodoItems/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Valores retornadosReturn values

O tipo de retorno dos GetTodoItems GetTodoItem métodos e é ActionResult <T> tipo.The return type of the GetTodoItems and GetTodoItem methods is ActionResult<T> type. O ASP.NET Core serializa automaticamente o objeto em JSON e grava o JSON no corpo da mensagem de resposta.ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. O código de resposta para esse tipo de retorno é 200 OK, supondo que não haja nenhuma exceção sem tratamento.The response code for this return type is 200 OK, assuming there are no unhandled exceptions. As exceções sem tratamento são convertidas em erros 5xx.Unhandled exceptions are translated into 5xx errors.

Os tipos de retorno ActionResult podem representar uma ampla variedade de códigos de status HTTP.ActionResult return types can represent a wide range of HTTP status codes. Por exemplo, GetTodoItem pode retornar dois valores de status diferentes:For example, GetTodoItem can return two different status values:

  • Se nenhum item corresponder à ID solicitada, o método retornará um código de erro de status 404 NotFound .If no item matches the requested ID, the method returns a 404 status NotFound error code.
  • Caso contrário, o método retornará 200 com um corpo de resposta JSON.Otherwise, the method returns 200 with a JSON response body. Retornar item resulta em uma resposta HTTP 200.Returning item results in an HTTP 200 response.

O método PutTodoItemThe PutTodoItem method

Examine o método PutTodoItem:Examine the PutTodoItem method:

// PUT: api/TodoItems/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItem é semelhante a PostTodoItem, exceto pelo uso de HTTP PUT.PutTodoItem is similar to PostTodoItem, except it uses HTTP PUT. A resposta é 204 (sem conteúdo).The response is 204 (No Content). De acordo com a especificação de HTTP, uma solicitação PUT exige que o cliente envie a entidade inteira atualizada, não apenas as alterações.According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the changes. Para dar suporte a atualizações parciais, use HTTP PATCH.To support partial updates, use HTTP PATCH.

Se você vir um erro ao chamar PutTodoItem, chame GET para garantir que existe um item no banco de dados.If you get an error calling PutTodoItem, call GET to ensure there's an item in the database.

Testar o método PutTodoItemTest the PutTodoItem method

Este exemplo usa um banco de dados na memória que deve ser inicializado toda vez que o aplicativo é iniciado.This sample uses an in-memory database that must be initialized each time the app is started. Deverá haver um item no banco de dados antes de você fazer uma chamada PUT.There must be an item in the database before you make a PUT call. Chame GET para garantir que há um item no banco de dados antes de fazer uma chamada PUT.Call GET to ensure there's an item in the database before making a PUT call.

Atualize o item de tarefas que tem a ID = 1 e defina seu nome como "feed fish" :Update the to-do item that has Id = 1 and set its name to "feed fish":

  {
    "Id":1,
    "name":"feed fish",
    "isComplete":true
  }

A seguinte imagem mostra a atualização do Postman:The following image shows the Postman update:

Console do Postman mostrando a resposta 204 (Sem conteúdo)

O método DeleteTodoItemThe DeleteTodoItem method

Examine o método DeleteTodoItem:Examine the DeleteTodoItem method:

// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

Testar o método DeleteTodoItemTest the DeleteTodoItem method

Use o Postman para excluir um item pendente:Use Postman to delete a to-do item:

  • Defina o método como DELETE.Set the method to DELETE.
  • Defina o URI do objeto a ser excluído (por exemplo, https://localhost:5001/api/TodoItems/1 ).Set the URI of the object to delete (for example https://localhost:5001/api/TodoItems/1).
  • Selecione Enviar.Select Send.

Evitar excesso de postagemPrevent over-posting

Atualmente, o aplicativo de exemplo expõe o TodoItem objeto inteiro.Currently the sample app exposes the entire TodoItem object. Os aplicativos de produção normalmente limitam os dados que são inseridos e retornados usando um subconjunto do modelo.Production apps typically limit the data that's input and returned using a subset of the model. Há várias razões por trás disso e a segurança é uma importante.There are multiple reasons behind this and security is a major one. O subconjunto de um modelo é geralmente conhecido como um objeto Transferência de Dados (DTO), um modelo de entrada ou um modelo de exibição.The subset of a model is usually referred to as a Data Transfer Object (DTO), input model, or view model. O dto é usado neste artigo.DTO is used in this article.

Um DTO pode ser usado para:A DTO may be used to:

  • Evitar sobrepostos.Prevent over-posting.
  • Oculte as propriedades que os clientes não devem exibir.Hide properties that clients are not supposed to view.
  • Omita algumas propriedades para reduzir o tamanho da carga.Omit some properties in order to reduce payload size.
  • Mesclar grafos de objeto que contêm objetos aninhados.Flatten object graphs that contain nested objects. Os gráficos de objeto achatados podem ser mais convenientes para os clientes.Flattened object graphs can be more convenient for clients.

Para demonstrar a abordagem do DTO, atualize a TodoItem classe para incluir um campo secreto:To demonstrate the DTO approach, update the TodoItem class to include a secret field:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
        public string Secret { get; set; }
    }
}

O campo segredo precisa ser ocultado deste aplicativo, mas um aplicativo administrativo pode optar por expô-lo.The secret field needs to be hidden from this app, but an administrative app could choose to expose it.

Verifique se você pode postar e obter o campo secreto.Verify you can post and get the secret field.

Criar um modelo de DTO:Create a DTO model:

public class TodoItemDTO
{
    public long Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
}

Atualize o TodoItemsController para usar TodoItemDTO :Update the TodoItemsController to use TodoItemDTO:

// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
    return await _context.TodoItems
        .Select(x => ItemToDTO(x))
        .ToListAsync();
}

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
    if (id != todoItemDTO.Id)
    {
        return BadRequest();
    }

    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    todoItem.Name = todoItemDTO.Name;
    todoItem.IsComplete = todoItemDTO.IsComplete;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
    {
        return NotFound();
    }

    return NoContent();
}

[HttpPost]
public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
{
    var todoItem = new TodoItem
    {
        IsComplete = todoItemDTO.IsComplete,
        Name = todoItemDTO.Name
    };

    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    return CreatedAtAction(
        nameof(GetTodoItem),
        new { id = todoItem.Id },
        ItemToDTO(todoItem));
}

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

private bool TodoItemExists(long id) =>
     _context.TodoItems.Any(e => e.Id == id);

private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
    new TodoItemDTO
    {
        Id = todoItem.Id,
        Name = todoItem.Name,
        IsComplete = todoItem.IsComplete
    };

Verifique se você não pode postar ou obter o campo secreto.Verify you can't post or get the secret field.

Chamar a API Web com o JavaScriptCall the web API with JavaScript

Consulte o tutorial: chamar uma API Web do ASP.NET Core com JavaScript.See Tutorial: Call an ASP.NET Core web API with JavaScript.

Neste tutorial, você aprenderá como:In this tutorial, you learn how to:

  • Criar um projeto de API Web.Create a web API project.
  • Adicione uma classe de modelo e um contexto de banco de dados.Add a model class and a database context.
  • Faça scaffold de um controlador com métodos CRUD.Scaffold a controller with CRUD methods.
  • Configure o roteamento, os caminhos de URL e os valores retornados.Configure routing, URL paths, and return values.
  • Chamar a API Web com o Postman.Call the web API with Postman.

No final, você terá uma API Web que pode gerenciar itens de "tarefas pendentes" armazenados em um banco de dados.At the end, you have a web API that can manage "to-do" items stored in a database.

Visão geralOverview

Este tutorial cria a seguinte API:This tutorial creates the following API:

APIAPI DescriçãoDescription Corpo da solicitaçãoRequest body Corpo da respostaResponse body
GET /api/TodoItems Obter todos os itens de tarefas pendentesGet all to-do items NenhumNone Matriz de itens de tarefas pendentesArray of to-do items
GET /api/TodoItems/{id} Obter um item por IDGet an item by ID NenhumNone Item de tarefas pendentesTo-do item
POST /api/TodoItems Adicionar um novo itemAdd a new item Item de tarefas pendentesTo-do item Item de tarefas pendentesTo-do item
PUT /api/TodoItems/{id} Atualizar um item   existenteUpdate an existing item   Item de tarefas pendentesTo-do item NenhumNone
DELETE /api/TodoItems/{id}    DELETE /api/TodoItems/{id}     Excluir um item   Delete an item     NenhumNone NenhumNone

O diagrama a seguir mostra o design do aplicativo.The following diagram shows the design of the app.

O cliente é representado por uma caixa à esquerda.

Pré-requisitosPrerequisites

Criar um projeto WebCreate a web project

  • No menu arquivo , selecione novo > projeto.From the File menu, select New > Project.
  • Selecione o modelo Aplicativo Web ASP.NET Core e clique em Próximo.Select the ASP.NET Core Web Application template and click Next.
  • Nomeie o projeto como TodoApi e clique em Criar.Name the project TodoApi and click Create.
  • Na caixa de diálogo criar um novo ASP.NET Core aplicativo Web , confirme se o .net Core e ASP.NET Core 3,1 estão selecionados.In the Create a new ASP.NET Core Web Application dialog, confirm that .NET Core and ASP.NET Core 3.1 are selected. Selecione o modelo API e clique em Criar.Select the API template and click Create.

Caixa de diálogo Novo projeto do VS

Testar a APITest the API

O modelo de projeto cria uma API WeatherForecast.The project template creates a WeatherForecast API. Chame o método Get em um navegador para testar o aplicativo.Call the Get method from a browser to test the app.

Pressione CTRL+F5 para executar o aplicativo.Press Ctrl+F5 to run the app. O Visual Studio inicia um navegador e navega para https://localhost:<port>/WeatherForecast, em que <port> é um número de porta escolhido aleatoriamente.Visual Studio launches a browser and navigates to https://localhost:<port>/WeatherForecast, where <port> is a randomly chosen port number.

Se você receber uma caixa de diálogo perguntando se você deve confiar no certificado do IIS Express, selecione Sim.If you get a dialog box that asks if you should trust the IIS Express certificate, select Yes. Na caixa de diálogo Aviso de Segurança exibida em seguida, selecione Sim.In the Security Warning dialog that appears next, select Yes.

Um JSON semelhante ao seguinte será retornado:JSON similar to the following is returned:

[
    {
        "date": "2019-07-16T19:04:05.7257911-06:00",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2019-07-17T19:04:05.7258461-06:00",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2019-07-18T19:04:05.7258467-06:00",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2019-07-19T19:04:05.7258471-06:00",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2019-07-20T19:04:05.7258474-06:00",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

Adicionar uma classe de modeloAdd a model class

Um modelo é um conjunto de classes que representam os dados gerenciados pelo aplicativo.A model is a set of classes that represent the data that the app manages. O modelo para esse aplicativo é uma única classe TodoItem.The model for this app is a single TodoItem class.

  • Em Gerenciador de soluções, clique com o botão direito do mouse no projeto.In Solution Explorer, right-click the project. Selecione Adicionar > nova pasta.Select Add > New Folder. Nomeie a pasta Models .Name the folder Models.

  • Clique com o botão direito do mouse na Models pasta e selecione Adicionar > classe.Right-click the Models folder and select Add > Class. Dê à classe o nome TodoItem e selecione Adicionar.Name the class TodoItem and select Add.

  • Substitua o código do modelo pelo seguinte código:Replace the template code with the following code:

public class TodoItem
{
    public long Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
}

A propriedade Id funciona como a chave exclusiva em um banco de dados relacional.The Id property functions as the unique key in a relational database.

As classes de modelo podem ir em qualquer lugar no projeto, mas a Models pasta é usada pela Convenção.Model classes can go anywhere in the project, but the Models folder is used by convention.

Adicionar um contexto de banco de dadosAdd a database context

O contexto de banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um modelo de dados.The database context is the main class that coordinates Entity Framework functionality for a data model. Essa classe é criada derivando-a da classe Microsoft.EntityFrameworkCore.DbContext.This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext class.

Adicionar pacotes NuGetAdd NuGet packages

  • No menu Ferramentas, selecione Gerenciador de Pacotes do NuGet > Gerenciar Pacotes do NuGet para a Solução.From the Tools menu, select NuGet Package Manager > Manage NuGet Packages for Solution.
  • Selecione a guia procurar e, em seguida, insira Microsoft. EntityFrameworkCore. inmemory na caixa de pesquisa.Select the Browse tab, and then enter Microsoft.EntityFrameworkCore.InMemory in the search box.
  • Selecione Microsoft. EntityFrameworkCore. inmemory no painel esquerdo.Select Microsoft.EntityFrameworkCore.InMemory in the left pane.
  • Selecione a caixa de seleção Projeto no painel direito e, em seguida, selecione Instalar.Select the Project check box in the right pane and then select Install.

Gerenciador de Pacotes NuGet

Adicione o contexto de banco de dados TodoContextAdd the TodoContext database context

  • Clique com o botão direito do mouse na Models pasta e selecione Adicionar > classe.Right-click the Models folder and select Add > Class. Nomeie a classe como TodoContext e clique em Adicionar.Name the class TodoContext and click Add.
  • Insira o seguinte código:Enter the following code:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models
    {
        public class TodoContext : DbContext
        {
            public TodoContext(DbContextOptions<TodoContext> options)
                : base(options)
            {
            }
    
            public DbSet<TodoItem> TodoItems { get; set; }
        }
    }
    

Registrar o contexto do banco de dadosRegister the database context

No ASP.NET Core, serviços como o contexto de BD precisam ser registrados no contêiner de DI (injeção de dependência).In ASP.NET Core, services such as the DB context must be registered with the dependency injection (DI) container. O contêiner fornece o serviço aos controladores.The container provides the service to controllers.

Atualize Startup.cs com o seguinte código realçado:Update Startup.cs with the following highlighted code:

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
               opt.UseInMemoryDatabase("TodoList"));
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

O código anterior:The preceding code:

  • Remove as declarações using não utilizadas.Removes unused using declarations.
  • Adiciona o contexto de banco de dados ao contêiner de DI.Adds the database context to the DI container.
  • Especifica que o contexto de banco de dados usará um banco de dados em memória.Specifies that the database context will use an in-memory database.

Faça scaffold de um controladorScaffold a controller

  • Clique com o botão direito do mouse na pasta Controllers.Right-click the Controllers folder.

  • Selecione Adicionar > Novo item com scaffold.Select Add > New Scaffolded Item.

  • Selecione Controlador de API com ações, usando o Entity Framework e, em seguida, selecione Adicionar.Select API Controller with actions, using Entity Framework, and then select Add.

  • Na caixa de diálogo Adicionar Controlador de API com ações, usando o Entity Framework:In the Add API Controller with actions, using Entity Framework dialog:

    • Selecione TodoItem (TodoApi. Models ) na classe Model.Select TodoItem (TodoApi.Models) in the Model class.
    • Selecione TodoContext (TodoApi. Models ) na classe de contexto de dados.Select TodoContext (TodoApi.Models) in the Data context class.
    • Selecione Adicionar.Select Add.

O código gerado:The generated code:

  • Marca a classe com o [ApiController] atributo.Marks the class with the [ApiController] attribute. Esse atributo indica se o controlador responde às solicitações da API Web.This attribute indicates that the controller responds to web API requests. Para saber mais sobre comportamentos específicos habilitados pelo atributo, consulte Criar APIs Web com o ASP.NET Core.For information about specific behaviors that the attribute enables, see Criar APIs Web com o ASP.NET Core.
  • Usa a DI para injetar o contexto de banco de dados (TodoContext) no controlador.Uses DI to inject the database context (TodoContext) into the controller. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.The database context is used in each of the CRUD methods in the controller.

Os modelos de ASP.NET Core para:The ASP.NET Core templates for:

  • Os controladores com exibições incluem [action] no modelo de rota.Controllers with views include [action] in the route template.
  • Os controladores de API não incluem [action] no modelo de rota.API controllers don't include [action] in the route template.

Quando o [action] token não está no modelo de rota, o nome da ação é excluído da rota.When the [action] token isn't in the route template, the action name is excluded from the route. Ou seja, o nome do método associado da ação não é usado na rota correspondente.That is, the action's associated method name isn't used in the matching route.

Examine o método criar do PostTodoItemExamine the PostTodoItem create method

Substitua a instrução return no PostTodoItem para usar o operador nameof:Replace the return statement in the PostTodoItem to use the nameof operator:

// POST: api/TodoItems
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

O código anterior é um método HTTP POST, conforme indicado pelo [HttpPost] atributo.The preceding code is an HTTP POST method, as indicated by the [HttpPost] attribute. O método obtém o valor do item pendente no corpo da solicitação HTTP.The method gets the value of the to-do item from the body of the HTTP request.

Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].For more information, see Attribute routing with Http[Verb] attributes.

O método CreatedAtAction:The CreatedAtAction method:

  • retorna um código de status HTTP 201 em caso de êxito.Returns an HTTP 201 status code if successful. HTTP 201 é a resposta padrão para um método HTTP POST que cria um novo recurso no servidor.HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.
  • Adiciona um cabeçalho de Local à resposta.Adds a Location header to the response. O cabeçalho Location especifica o URI do item de tarefas pendentes recém-criado.The Location header specifies the URI of the newly created to-do item. Para obter mais informações, confira 10.2.2 201 Criado.For more information, see 10.2.2 201 Created.
  • Faz referência à ação GetTodoItem para criar o URI de Location do cabeçalho.References the GetTodoItem action to create the Location header's URI. A palavra-chave nameof do C# é usada para evitar o hard-coding do nome da ação, na chamada CreatedAtAction.The C# nameof keyword is used to avoid hard-coding the action name in the CreatedAtAction call.

Instale o PostmanInstall Postman

Este tutorial usa o Postman para testar a API Web.This tutorial uses Postman to test the web API.

  • Instalar o postmasterInstall Postman
  • Inicie o aplicativo Web.Start the web app.
  • Inicie o Postman.Start Postman.
  • Desabilite a Verificação do certificado SSLDisable SSL certificate verification
    • Em Arquivo > Configurações (guia Geral), desabilite Verificação de certificado SSL.From File > Settings (General tab), disable SSL certificate verification.

      Aviso

      Habilite novamente a verificação do certificado SSL depois de testar o controlador.Re-enable SSL certificate verification after testing the controller.

Teste o PostTodoItem com o PostmanTest PostTodoItem with Postman

  • Crie uma solicitação.Create a new request.

  • Defina o método HTTP como POST.Set the HTTP method to POST.

  • Defina o URI como https://localhost:<port>/api/TodoItems .Set the URI to https://localhost:<port>/api/TodoItems. Por exemplo, https://localhost:5001/api/TodoItems.For example, https://localhost:5001/api/TodoItems.

  • Selecione a guia Corpo.Select the Body tab.

  • Selecione o botão de opção bruto.Select the raw radio button.

  • Defina o tipo como JSON (aplicativo/json).Set the type to JSON (application/json).

  • No corpo da solicitação, insira JSON para um item pendente:In the request body enter JSON for a to-do item:

    {
      "name":"walk dog",
      "isComplete":true
    }
    
  • Selecione Enviar.Select Send.

    Postman com a solicitação Create

Testar o URI do cabeçalho do local com o postmasterTest the location header URI with Postman

  • Selecione a guia Cabeçalhos no painel Resposta.Select the Headers tab in the Response pane.

  • Copie o valor do cabeçalho Local:Copy the Location header value:

    Guia Cabeçalhos do console do Postman

  • Defina o método HTTP como GET.Set the HTTP method to GET.

  • Defina o URI como https://localhost:<port>/api/TodoItems/1 .Set the URI to https://localhost:<port>/api/TodoItems/1. Por exemplo, https://localhost:5001/api/TodoItems/1.For example, https://localhost:5001/api/TodoItems/1.

  • Selecione Enviar.Select Send.

Examine os métodos GETExamine the GET methods

Esses métodos implementam dois pontos de extremidade GET:These methods implement two GET endpoints:

  • GET /api/TodoItems
  • GET /api/TodoItems/{id}

Teste o aplicativo chamando os dois pontos de extremidade de um navegador ou do Postman.Test the app by calling the two endpoints from a browser or Postman. Por exemplo: For example:

  • https://localhost:5001/api/TodoItems
  • https://localhost:5001/api/TodoItems/1

Uma resposta semelhante à seguinte é produzida pela chamada a GetTodoItems:A response similar to the following is produced by the call to GetTodoItems:

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]

Teste o GET com o PostmanTest Get with Postman

  • Crie uma solicitação.Create a new request.
  • Defina o método HTTP como GET.Set the HTTP method to GET.
  • Defina o URI de solicitação como https://localhost:<port>/api/TodoItems .Set the request URI to https://localhost:<port>/api/TodoItems. Por exemplo, https://localhost:5001/api/TodoItems.For example, https://localhost:5001/api/TodoItems.
  • Defina Exibição de dois painéis no Postman.Set Two pane view in Postman.
  • Selecione Enviar.Select Send.

Este aplicativo usa um banco de dados em memória.This app uses an in-memory database. Se o aplicativo for interrompido e iniciado, a solicitação GET anterior não retornará nenhum dado.If the app is stopped and started, the preceding GET request will not return any data. Se nenhum dado for retornado, execute POST de dados no aplicativo.If no data is returned, POST data to the app.

Roteamento e caminhos de URLRouting and URL paths

O [HttpGet] atributo denota um método que responde a uma solicitação HTTP Get.The [HttpGet] attribute denotes a method that responds to an HTTP GET request. O caminho da URL de cada método é construído da seguinte maneira:The URL path for each method is constructed as follows:

  • Comece com a cadeia de caracteres de modelo no atributo Route do controlador:Start with the template string in the controller's Route attribute:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    {
        private readonly TodoContext _context;
    
        public TodoItemsController(TodoContext context)
        {
            _context = context;
        }
    
  • Substitua [controller] pelo nome do controlador, que é o nome de classe do controlador menos o sufixo "Controlador" por convenção.Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. Para esta amostra, o nome da classe do controlador é TodoItems Controller. Portanto, o nome do controlador é "TodoItems".For this sample, the controller class name is TodoItems Controller, so the controller name is "TodoItems". O roteamento do ASP.NET Core não diferencia maiúsculas de minúsculas.ASP.NET Core routing is case insensitive.

  • Se o atributo [HttpGet] tiver um modelo de rota (por exemplo, [HttpGet("products")]), acrescente isso ao caminho.If the [HttpGet] attribute has a route template (for example, [HttpGet("products")]), append that to the path. Esta amostra não usa um modelo.This sample doesn't use a template. Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].For more information, see Attribute routing with Http[Verb] attributes.

No método GetTodoItem a seguir, "{id}" é uma variável de espaço reservado para o identificador exclusivo do item pendente.In the following GetTodoItem method, "{id}" is a placeholder variable for the unique identifier of the to-do item. Quando GetTodoItem é invocado, o valor de "{id}" na URL é fornecido para o método em seu id parâmetro.When GetTodoItem is invoked, the value of "{id}" in the URL is provided to the method in its id parameter.

// GET: api/TodoItems/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Valores retornadosReturn values

O tipo de retorno dos GetTodoItems GetTodoItem métodos e é ActionResult <T> tipo.The return type of the GetTodoItems and GetTodoItem methods is ActionResult<T> type. O ASP.NET Core serializa automaticamente o objeto em JSON e grava o JSON no corpo da mensagem de resposta.ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. O código de resposta para esse tipo de retorno é 200, supondo que não haja nenhuma exceção sem tratamento.The response code for this return type is 200, assuming there are no unhandled exceptions. As exceções sem tratamento são convertidas em erros 5xx.Unhandled exceptions are translated into 5xx errors.

Os tipos de retorno ActionResult podem representar uma ampla variedade de códigos de status HTTP.ActionResult return types can represent a wide range of HTTP status codes. Por exemplo, GetTodoItem pode retornar dois valores de status diferentes:For example, GetTodoItem can return two different status values:

  • Se nenhum item corresponder à ID solicitada, o método retornará um NotFound código de erro 404.If no item matches the requested ID, the method returns a 404 NotFound error code.
  • Caso contrário, o método retornará 200 com um corpo de resposta JSON.Otherwise, the method returns 200 with a JSON response body. Retornar item resulta em uma resposta HTTP 200.Returning item results in an HTTP 200 response.

O método PutTodoItemThe PutTodoItem method

Examine o método PutTodoItem:Examine the PutTodoItem method:

// PUT: api/TodoItems/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItem é semelhante a PostTodoItem, exceto pelo uso de HTTP PUT.PutTodoItem is similar to PostTodoItem, except it uses HTTP PUT. A resposta é 204 (sem conteúdo).The response is 204 (No Content). De acordo com a especificação de HTTP, uma solicitação PUT exige que o cliente envie a entidade inteira atualizada, não apenas as alterações.According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the changes. Para dar suporte a atualizações parciais, use HTTP PATCH.To support partial updates, use HTTP PATCH.

Se você vir um erro ao chamar PutTodoItem, chame GET para garantir que existe um item no banco de dados.If you get an error calling PutTodoItem, call GET to ensure there's an item in the database.

Testar o método PutTodoItemTest the PutTodoItem method

Este exemplo usa um banco de dados na memória que deve ser inicializado toda vez que o aplicativo é iniciado.This sample uses an in-memory database that must be initialized each time the app is started. Deverá haver um item no banco de dados antes de você fazer uma chamada PUT.There must be an item in the database before you make a PUT call. Chame GET para garantir que há um item no banco de dados antes de fazer uma chamada PUT.Call GET to ensure there's an item in the database before making a PUT call.

Atualize o item de tarefas que tem a ID = 1 e defina seu nome como "alimentar feed":Update the to-do item that has Id = 1 and set its name to "feed fish":

  {
    "id":1,
    "name":"feed fish",
    "isComplete":true
  }

A seguinte imagem mostra a atualização do Postman:The following image shows the Postman update:

Console do Postman mostrando a resposta 204 (Sem conteúdo)

O método DeleteTodoItemThe DeleteTodoItem method

Examine o método DeleteTodoItem:Examine the DeleteTodoItem method:

// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<ActionResult<TodoItem>> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return todoItem;
}

Testar o método DeleteTodoItemTest the DeleteTodoItem method

Use o Postman para excluir um item pendente:Use Postman to delete a to-do item:

  • Defina o método como DELETE.Set the method to DELETE.
  • Defina o URI do objeto a ser excluído (por exemplo, https://localhost:5001/api/TodoItems/1 ).Set the URI of the object to delete (for example https://localhost:5001/api/TodoItems/1).
  • Selecione Enviar.Select Send.

Evitar excesso de postagemPrevent over-posting

Atualmente, o aplicativo de exemplo expõe o TodoItem objeto inteiro.Currently the sample app exposes the entire TodoItem object. Os aplicativos de produção normalmente limitam os dados que são inseridos e retornados usando um subconjunto do modelo.Production apps typically limit the data that's input and returned using a subset of the model. Há várias razões por trás disso e a segurança é uma importante.There are multiple reasons behind this and security is a major one. O subconjunto de um modelo é geralmente conhecido como um objeto Transferência de Dados (DTO), um modelo de entrada ou um modelo de exibição.The subset of a model is usually referred to as a Data Transfer Object (DTO), input model, or view model. O dto é usado neste artigo.DTO is used in this article.

Um DTO pode ser usado para:A DTO may be used to:

  • Evitar sobrepostos.Prevent over-posting.
  • Oculte as propriedades que os clientes não devem exibir.Hide properties that clients are not supposed to view.
  • Omita algumas propriedades para reduzir o tamanho da carga.Omit some properties in order to reduce payload size.
  • Mesclar grafos de objeto que contêm objetos aninhados.Flatten object graphs that contain nested objects. Os gráficos de objeto achatados podem ser mais convenientes para os clientes.Flattened object graphs can be more convenient for clients.

Para demonstrar a abordagem do DTO, atualize a TodoItem classe para incluir um campo secreto:To demonstrate the DTO approach, update the TodoItem class to include a secret field:

public class TodoItem
{
    public long Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
    public string Secret { get; set; }
}

O campo segredo precisa ser ocultado deste aplicativo, mas um aplicativo administrativo pode optar por expô-lo.The secret field needs to be hidden from this app, but an administrative app could choose to expose it.

Verifique se você pode postar e obter o campo secreto.Verify you can post and get the secret field.

Criar um modelo de DTO:Create a DTO model:

public class TodoItemDTO
{
    public long Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
}

Atualize o TodoItemsController para usar TodoItemDTO :Update the TodoItemsController to use TodoItemDTO:

    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
    {
        return await _context.TodoItems
            .Select(x => ItemToDTO(x))
            .ToListAsync();
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        return ItemToDTO(todoItem);
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
    {
        if (id != todoItemDTO.Id)
        {
            return BadRequest();
        }

        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        todoItem.Name = todoItemDTO.Name;
        todoItem.IsComplete = todoItemDTO.IsComplete;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
        {
            return NotFound();
        }

        return NoContent();
    }

    [HttpPost]
    public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
    {
        var todoItem = new TodoItem
        {
            IsComplete = todoItemDTO.IsComplete,
            Name = todoItemDTO.Name
        };

        _context.TodoItems.Add(todoItem);
        await _context.SaveChangesAsync();

        return CreatedAtAction(
            nameof(GetTodoItem),
            new { id = todoItem.Id },
            ItemToDTO(todoItem));
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        _context.TodoItems.Remove(todoItem);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    private bool TodoItemExists(long id) =>
         _context.TodoItems.Any(e => e.Id == id);

    private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
        new TodoItemDTO
        {
            Id = todoItem.Id,
            Name = todoItem.Name,
            IsComplete = todoItem.IsComplete
        };       
}

Verifique se você não pode postar ou obter o campo secreto.Verify you can't post or get the secret field.

Chamar a API Web com o JavaScriptCall the web API with JavaScript

Consulte o tutorial: chamar uma API Web do ASP.NET Core com JavaScript.See Tutorial: Call an ASP.NET Core web API with JavaScript.

Neste tutorial, você aprenderá como:In this tutorial, you learn how to:

  • Criar um projeto de API Web.Create a web API project.
  • Adicione uma classe de modelo e um contexto de banco de dados.Add a model class and a database context.
  • Adicionar um controlador.Add a controller.
  • Adicionar métodos CRUD.Add CRUD methods.
  • Configurar o roteamento e caminhos de URL.Configure routing and URL paths.
  • Especificar os valores retornados.Specify return values.
  • Chamar a API Web com o Postman.Call the web API with Postman.
  • Chamar a API Web com o JavaScript.Call the web API with JavaScript.

No final, você terá uma API Web que pode gerenciar itens de "tarefas pendentes" armazenados em um banco de dados relacional.At the end, you have a web API that can manage "to-do" items stored in a relational database.

Visão geral 2,1Overview 2.1

Este tutorial cria a seguinte API:This tutorial creates the following API:

APIAPI DescriçãoDescription Corpo da solicitaçãoRequest body Corpo da respostaResponse body
GET /api/TodoItemsGET /api/TodoItems Obter todos os itens de tarefas pendentesGet all to-do items NenhumNone Matriz de itens de tarefas pendentesArray of to-do items
GET /api/TodoItems/{id}GET /api/TodoItems/{id} Obter um item por IDGet an item by ID NenhumNone Item de tarefas pendentesTo-do item
POST /api/TodoItemsPOST /api/TodoItems Adicionar um novo itemAdd a new item Item de tarefas pendentesTo-do item Item de tarefas pendentesTo-do item
PUT /api/TodoItems/{id}PUT /api/TodoItems/{id} Atualizar um item   existenteUpdate an existing item   Item de tarefas pendentesTo-do item NenhumNone
EXCLUIR/api/TodoItems/{id}   DELETE /api/TodoItems/{id}     Excluir um item   Delete an item     NenhumNone NenhumNone

O diagrama a seguir mostra o design do aplicativo.The following diagram shows the design of the app.

O cliente é representado por uma caixa à esquerda.

Pré-requisitos 2,1Prerequisites 2.1

Aviso

Se você usar o Visual Studio 2017, confira problema de dotnet/sdk nº 3124 para obter informações sobre as versões do SDK do .NET Core que não funcionam com o Visual Studio.If you use Visual Studio 2017, see dotnet/sdk issue #3124 for information about .NET Core SDK versions that don't work with Visual Studio.

Criar um projeto Web 2,1Create a web project 2.1

  • No menu arquivo , selecione novo > projeto.From the File menu, select New > Project.
  • Selecione o modelo Aplicativo Web ASP.NET Core e clique em Próximo.Select the ASP.NET Core Web Application template and click Next.
  • Nomeie o projeto como TodoApi e clique em Criar.Name the project TodoApi and click Create.
  • Na caixa de diálogo Criar um aplicativo Web ASP.NET Core, confirme se .NET Core e ASP.NET Core 2.2 estão selecionados.In the Create a new ASP.NET Core Web Application dialog, confirm that .NET Core and ASP.NET Core 2.2 are selected. Selecione o modelo API e clique em Criar.Select the API template and click Create. Não selecione Habilitar Suporte ao Docker.Don't select Enable Docker Support.

Caixa de diálogo Novo projeto do VS

Testar a API 2,1Test the API 2.1

O modelo de projeto cria uma API values.The project template creates a values API. Chame o método Get em um navegador para testar o aplicativo.Call the Get method from a browser to test the app.

Pressione CTRL+F5 para executar o aplicativo.Press Ctrl+F5 to run the app. O Visual Studio inicia um navegador e navega para https://localhost:<port>/api/values, em que <port> é um número de porta escolhido aleatoriamente.Visual Studio launches a browser and navigates to https://localhost:<port>/api/values, where <port> is a randomly chosen port number.

Se você receber uma caixa de diálogo perguntando se você deve confiar no certificado do IIS Express, selecione Sim.If you get a dialog box that asks if you should trust the IIS Express certificate, select Yes. Na caixa de diálogo Aviso de Segurança exibida em seguida, selecione Sim.In the Security Warning dialog that appears next, select Yes.

O JSON a seguir será retornado:The following JSON is returned:

["value1","value2"]

Adicionar uma classe de modelo 2,1Add a model class 2.1

Um modelo é um conjunto de classes que representam os dados gerenciados pelo aplicativo.A model is a set of classes that represent the data that the app manages. O modelo para esse aplicativo é uma única classe TodoItem.The model for this app is a single TodoItem class.

  • Em Gerenciador de soluções, clique com o botão direito do mouse no projeto.In Solution Explorer, right-click the project. Selecione Adicionar > nova pasta.Select Add > New Folder. Nomeie a pasta Models .Name the folder Models.

  • Clique com o botão direito do mouse na Models pasta e selecione Adicionar > classe.Right-click the Models folder and select Add > Class. Dê à classe o nome TodoItem e selecione Adicionar.Name the class TodoItem and select Add.

  • Substitua o código do modelo pelo seguinte código:Replace the template code with the following code:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

A propriedade Id funciona como a chave exclusiva em um banco de dados relacional.The Id property functions as the unique key in a relational database.

As classes de modelo podem ir em qualquer lugar no projeto, mas a Models pasta é usada pela Convenção.Model classes can go anywhere in the project, but the Models folder is used by convention.

Adicionar um contexto de banco de dados 2,1Add a database context 2.1

O contexto de banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um modelo de dados.The database context is the main class that coordinates Entity Framework functionality for a data model. Essa classe é criada derivando-a da classe Microsoft.EntityFrameworkCore.DbContext.This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext class.

  • Clique com o botão direito do mouse na Models pasta e selecione Adicionar > classe.Right-click the Models folder and select Add > Class. Nomeie a classe como TodoContext e clique em Adicionar.Name the class TodoContext and click Add.
  • Substitua o código do modelo pelo seguinte código:Replace the template code with the following code:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models
    {
        public class TodoContext : DbContext
        {
            public TodoContext(DbContextOptions<TodoContext> options)
                : base(options)
            {
            }
    
            public DbSet<TodoItem> TodoItems { get; set; }
        }
    }
    

Registrar o contexto de banco de dados 2,1Register the database context 2.1

No ASP.NET Core, serviços como o contexto de BD precisam ser registrados no contêiner de DI (injeção de dependência).In ASP.NET Core, services such as the DB context must be registered with the dependency injection (DI) container. O contêiner fornece o serviço aos controladores.The container provides the service to controllers.

Atualize Startup.cs com o seguinte código realçado:Update Startup.cs with the following highlighted code:

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the 
        //container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
                opt.UseInMemoryDatabase("TodoList"));
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP 
        //request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for 
                // production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMvc();
        }
    }
}

O código anterior:The preceding code:

  • Remove as declarações using não utilizadas.Removes unused using declarations.
  • Adiciona o contexto de banco de dados ao contêiner de DI.Adds the database context to the DI container.
  • Especifica que o contexto de banco de dados usará um banco de dados em memória.Specifies that the database context will use an in-memory database.

Adicionar um controlador 2,1Add a controller 2.1

  • Clique com o botão direito do mouse na pasta Controllers.Right-click the Controllers folder.

  • Selecione Adicionar > novo item.Select Add > New Item.

  • Na caixa de diálogo Adicionar Novo Item, selecione o modelo Classe do Controlador de API.In the Add New Item dialog, select the API Controller Class template.

  • Dê à classe o nome TodoController e selecione Adicionar.Name the class TodoController, and select Add.

    Caixa de diálogo Adicionar Novo Item com o controlador na caixa de pesquisa e o controlador da API Web selecionados

  • Substitua o código do modelo pelo seguinte código:Replace the template code with the following code:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using TodoApi.Models;
    
    namespace TodoApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class TodoController : ControllerBase
        {
            private readonly TodoContext _context;
    
            public TodoController(TodoContext context)
            {
                _context = context;
    
                if (_context.TodoItems.Count() == 0)
                {
                    // Create a new TodoItem if collection is empty,
                    // which means you can't delete all TodoItems.
                    _context.TodoItems.Add(new TodoItem { Name = "Item1" });
                    _context.SaveChanges();
                }
            }
        }
    }
    

O código anterior:The preceding code:

  • Define uma classe de controlador de API sem métodos.Defines an API controller class without methods.
  • Marca a classe com o [ApiController] atributo.Marks the class with the [ApiController] attribute. Esse atributo indica se o controlador responde às solicitações da API Web.This attribute indicates that the controller responds to web API requests. Para saber mais sobre comportamentos específicos habilitados pelo atributo, consulte Criar APIs Web com o ASP.NET Core.For information about specific behaviors that the attribute enables, see Criar APIs Web com o ASP.NET Core.
  • Usa a DI para injetar o contexto de banco de dados (TodoContext) no controlador.Uses DI to inject the database context (TodoContext) into the controller. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.The database context is used in each of the CRUD methods in the controller.
  • Adiciona um item chamado Item1 ao banco de dados se o banco de dados está vazio.Adds an item named Item1 to the database if the database is empty. Esse código está no construtor, de modo que ele seja executado sempre que há uma nova solicitação HTTP.This code is in the constructor, so it runs every time there's a new HTTP request. Se você excluir todos os itens, o construtor criará Item1 novamente na próxima vez que um método de API for chamado.If you delete all items, the constructor creates Item1 again the next time an API method is called. Portanto, pode parecer que a exclusão não funcionou quando ela realmente funcionou.So it may look like the deletion didn't work when it actually did work.

Adicionar os métodos get 2,1Add Get methods 2.1

Para fornecer uma API que recupera itens pendentes, adicione os seguintes métodos à classe TodoController:To provide an API that retrieves to-do items, add the following methods to the TodoController class:

// GET: api/Todo
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
    return await _context.TodoItems.ToListAsync();
}

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Esses métodos implementam dois pontos de extremidade GET:These methods implement two GET endpoints:

  • GET /api/todo
  • GET /api/todo/{id}

Interrompa o aplicativo se ele ainda estiver em execução.Stop the app if it's still running. Em seguida, execute-o novamente para incluir as alterações mais recentes.Then run it again to include the latest changes.

Teste o aplicativo chamando os dois pontos de extremidade em um navegador.Test the app by calling the two endpoints from a browser. Por exemplo: For example:

  • https://localhost:<port>/api/todo
  • https://localhost:<port>/api/todo/1

A seguinte resposta HTTP é produzida pela chamada a GetTodoItems:The following HTTP response is produced by the call to GetTodoItems:

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]

Caminhos de roteamento e URL 2,1Routing and URL paths 2.1

O [HttpGet] atributo denota um método que responde a uma solicitação HTTP Get.The [HttpGet] attribute denotes a method that responds to an HTTP GET request. O caminho da URL de cada método é construído da seguinte maneira:The URL path for each method is constructed as follows:

  • Comece com a cadeia de caracteres de modelo no atributo Route do controlador:Start with the template string in the controller's Route attribute:

    namespace TodoApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class TodoController : ControllerBase
        {
            private readonly TodoContext _context;
    
  • Substitua [controller] pelo nome do controlador, que é o nome de classe do controlador menos o sufixo "Controlador" por convenção.Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. Para esta amostra, o nome da classe do controlador é Todo Controller e, portanto, o nome do controlador é "todo".For this sample, the controller class name is Todo Controller, so the controller name is "todo". O roteamento do ASP.NET Core não diferencia maiúsculas de minúsculas.ASP.NET Core routing is case insensitive.

  • Se o atributo [HttpGet] tiver um modelo de rota (por exemplo, [HttpGet("products")]), acrescente isso ao caminho.If the [HttpGet] attribute has a route template (for example, [HttpGet("products")]), append that to the path. Esta amostra não usa um modelo.This sample doesn't use a template. Para obter mais informações, confira Roteamento de atributo com atributos Http[Verb].For more information, see Attribute routing with Http[Verb] attributes.

No método GetTodoItem a seguir, "{id}" é uma variável de espaço reservado para o identificador exclusivo do item pendente.In the following GetTodoItem method, "{id}" is a placeholder variable for the unique identifier of the to-do item. Quando GetTodoItem é invocado, o valor de "{id}" na URL é fornecido para o método no parâmetro id.When GetTodoItem is invoked, the value of "{id}" in the URL is provided to the method in itsid parameter.

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Valores de retorno 2,1Return values 2.1

O tipo de retorno dos GetTodoItems GetTodoItem métodos e é ActionResult <T> tipo.The return type of the GetTodoItems and GetTodoItem methods is ActionResult<T> type. O ASP.NET Core serializa automaticamente o objeto em JSON e grava o JSON no corpo da mensagem de resposta.ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. O código de resposta para esse tipo de retorno é 200, supondo que não haja nenhuma exceção sem tratamento.The response code for this return type is 200, assuming there are no unhandled exceptions. As exceções sem tratamento são convertidas em erros 5xx.Unhandled exceptions are translated into 5xx errors.

Os tipos de retorno ActionResult podem representar uma ampla variedade de códigos de status HTTP.ActionResult return types can represent a wide range of HTTP status codes. Por exemplo, GetTodoItem pode retornar dois valores de status diferentes:For example, GetTodoItem can return two different status values:

  • Se nenhum item corresponder à ID solicitada, o método retornará um NotFound código de erro 404.If no item matches the requested ID, the method returns a 404 NotFound error code.
  • Caso contrário, o método retornará 200 com um corpo de resposta JSON.Otherwise, the method returns 200 with a JSON response body. Retornar item resulta em uma resposta HTTP 200.Returning item results in an HTTP 200 response.

Testar o método GetTodoItems 2,1Test the GetTodoItems method 2.1

Este tutorial usa o Postman para testar a API Web.This tutorial uses Postman to test the web API.

  • Instalar o Postman.Install Postman.
  • Inicie o aplicativo Web.Start the web app.
  • Inicie o Postman.Start Postman.
  • Desabilite a verificação de certificado SSL.Disable SSL certificate verification.
  • Em Arquivo > Configurações (guia Geral), desabilite Verificação de certificado SSL.From File > Settings (General tab), disable SSL certificate verification.

Aviso

Habilite novamente a verificação do certificado SSL depois de testar o controlador.Re-enable SSL certificate verification after testing the controller.

  • Crie uma solicitação.Create a new request.
    • Defina o método HTTP como GET.Set the HTTP method to GET.
    • Defina o URI de solicitação como https://localhost:<port>/api/todo .Set the request URI to https://localhost:<port>/api/todo. Por exemplo, https://localhost:5001/api/todo.For example, https://localhost:5001/api/todo.
  • Defina Exibição de dois painéis no Postman.Set Two pane view in Postman.
  • Selecione Enviar.Select Send.

Postman com solicitação GET

Adicionar um método Create 2,1Add a Create method 2.1

Adicione o seguinte método PostTodoItem dentro de Controllers/TodoController.cs:Add the following PostTodoItem method inside of Controllers/TodoController.cs:

// POST: api/Todo
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
}

O código anterior é um método HTTP POST, conforme indicado pelo [HttpPost] atributo.The preceding code is an HTTP POST method, as indicated by the [HttpPost] attribute. O método obtém o valor do item pendente no corpo da solicitação HTTP.The method gets the value of the to-do item from the body of the HTTP request.

O método CreatedAtAction:The CreatedAtAction method:

  • retorna um código de status HTTP 201 em caso de êxito.Returns an HTTP 201 status code, if successful. HTTP 201 é a resposta padrão para um método HTTP POST que cria um novo recurso no servidor.HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.

  • Adiciona um cabeçalho Location à resposta.Adds a Location header to the response. O cabeçalho Location especifica o URI do item de tarefas pendentes recém-criado.The Location header specifies the URI of the newly created to-do item. Para obter mais informações, confira 10.2.2 201 Criado.For more information, see 10.2.2 201 Created.

  • Faz referência à ação GetTodoItem para criar o URI de Location do cabeçalho.References the GetTodoItem action to create the Location header's URI. A palavra-chave nameof do C# é usada para evitar o hard-coding do nome da ação, na chamada CreatedAtAction.The C# nameof keyword is used to avoid hard-coding the action name in the CreatedAtAction call.

    // GET: api/Todo/5
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
    
        if (todoItem == null)
        {
            return NotFound();
        }
    
        return todoItem;
    }
    

Testar o método PostTodoItem 2,1Test the PostTodoItem method 2.1

  • Compile o projeto.Build the project.

  • No Postman, defina o método HTTP como POST.In Postman, set the HTTP method to POST.

  • Defina o URI como https://localhost:<port>/api/Todo .Set the URI to https://localhost:<port>/api/Todo. Por exemplo, https://localhost:5001/api/Todo.For example, https://localhost:5001/api/Todo.

  • Selecione a guia Corpo.Select the Body tab.

  • Selecione o botão de opção bruto.Select the raw radio button.

  • Defina o tipo como JSON (aplicativo/json).Set the type to JSON (application/json).

  • No corpo da solicitação, insira JSON para um item pendente:In the request body enter JSON for a to-do item:

    {
      "name":"walk dog",
      "isComplete":true
    }
    
  • Selecione Enviar.Select Send.

    Postman com a solicitação Create

    Se você receber um erro 405 Método Não Permitido, provavelmente, esse será o resultado da não compilação do projeto após a adição do método PostTodoItem.If you get a 405 Method Not Allowed error, it's probably the result of not compiling the project after adding the PostTodoItem method.

Testar o URI do cabeçalho do local 2,1Test the location header URI 2.1

  • Selecione a guia Cabeçalhos no painel Resposta.Select the Headers tab in the Response pane.

  • Copie o valor do cabeçalho Local:Copy the Location header value:

    Guia Cabeçalhos do console do Postman

  • Defina o método como GET.Set the method to GET.

  • Defina o URI como https://localhost:<port>/api/TodoItems/2 .Set the URI to https://localhost:<port>/api/TodoItems/2. Por exemplo, https://localhost:5001/api/TodoItems/2.For example, https://localhost:5001/api/TodoItems/2.

  • Selecione Enviar.Select Send.

Adicionar um método PutTodoItem 2,1Add a PutTodoItem method 2.1

Em seguida, adicione o método PutTodoItem a seguir:Add the following PutTodoItem method:

// PUT: api/Todo/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem item)
{
    if (id != item.Id)
    {
        return BadRequest();
    }

    _context.Entry(item).State = EntityState.Modified;
    await _context.SaveChangesAsync();

    return NoContent();
}

PutTodoItem é semelhante a PostTodoItem, exceto pelo uso de HTTP PUT.PutTodoItem is similar to PostTodoItem, except it uses HTTP PUT. A resposta é 204 (sem conteúdo).The response is 204 (No Content). De acordo com a especificação de HTTP, uma solicitação PUT exige que o cliente envie a entidade inteira atualizada, não apenas as alterações.According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the changes. Para dar suporte a atualizações parciais, use HTTP PATCH.To support partial updates, use HTTP PATCH.

Se você vir um erro ao chamar PutTodoItem, chame GET para garantir que existe um item no banco de dados.If you get an error calling PutTodoItem, call GET to ensure there's an item in the database.

Testar o método PutTodoItem 2,1Test the PutTodoItem method 2.1

Este exemplo usa um banco de dados na memória que deve ser inicializado toda vez que o aplicativo é iniciado.This sample uses an in-memory database that must be initialized each time the app is started. Deverá haver um item no banco de dados antes de você fazer uma chamada PUT.There must be an item in the database before you make a PUT call. Chame GET para garantir que há um item no banco de dados antes de fazer uma chamada PUT.Call GET to ensure there's an item in the database before making a PUT call.

Atualize o item de tarefas que tem a ID = 1 e defina seu nome como "alimentar feed":Update the to-do item that has Id = 1 and set its name to "feed fish":

  {
    "id":1,
    "name":"feed fish",
    "isComplete":true
  }

A seguinte imagem mostra a atualização do Postman:The following image shows the Postman update:

Console do Postman mostrando a resposta 204 (Sem conteúdo)

Adicionar um método DeleteTodoItem 2,1Add a DeleteTodoItem method 2.1

Em seguida, adicione o método DeleteTodoItem a seguir:Add the following DeleteTodoItem method:

// DELETE: api/Todo/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

A resposta DeleteTodoItem é 204 (Sem conteúdo).The DeleteTodoItem response is 204 (No Content).

Testar o método DeleteTodoItem 2,1Test the DeleteTodoItem method 2.1

Use o Postman para excluir um item pendente:Use Postman to delete a to-do item:

  • Defina o método como DELETE.Set the method to DELETE.
  • Defina o URI do objeto a ser excluído (por exemplo, https://localhost:5001/api/todo/1 ).Set the URI of the object to delete (for example, https://localhost:5001/api/todo/1).
  • Selecione Enviar.Select Send.

O aplicativo de exemplo permite que você exclua todos os itens.The sample app allows you to delete all the items. No entanto, quando o último item é excluído, um novo é criado pelo construtor de classe de modelo na próxima vez que a API for chamada.However, when the last item is deleted, a new one is created by the model class constructor the next time the API is called.

Chamar a API Web com JavaScript 2,1Call the web API with JavaScript 2.1

Nesta seção, é adicionada uma página HTML que usa o JavaScript para chamar a API Web.In this section, an HTML page is added that uses JavaScript to call the web API. o jQuery inicia a solicitação.jQuery initiates the request. O JavaScript atualiza a página com os detalhes da resposta da API Web.JavaScript updates the page with the details from the web API's response.

Configurar o aplicativo para servir arquivos estáticos e habilitar o mapeamento de arquivo padrão atualizando Startup.cs com o código realçado a seguir:Configure the app to serve static files and enable default file mapping by updating Startup.cs with the following highlighted code:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        // The default HSTS value is 30 days. You may want to change this for 
        // production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseDefaultFiles();
    app.UseStaticFiles();
    app.UseHttpsRedirection();
    app.UseMvc();
}

Crie uma pasta wwwroot no diretório do projeto.Create a wwwroot folder in the project directory.

Adicione um arquivo HTML chamado index.html ao diretório wwwroot.Add an HTML file named index.html to the wwwroot directory. Substitua seu conteúdo pela seguinte marcação:Replace its contents with the following markup:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>To-do CRUD</title>
    <style>
        input[type='submit'], button, [aria-label] {
            cursor: pointer;
        }

        #spoiler {
            display: none;
        }

        table {
            font-family: Arial, sans-serif;
            border: 1px solid;
            border-collapse: collapse;
        }

        th {
            background-color: #0066CC;
            color: white;
        }

        td {
            border: 1px solid;
            padding: 5px;
        }
    </style>
</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="spoiler">
        <h3>Edit</h3>
        <form class="my-form">
            <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="https://code.jquery.com/jquery-3.3.1.min.js"
            integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
            crossorigin="anonymous"></script>
    <script src="site.js"></script>
</body>
</html>

Adicione um arquivo JavaScript chamado site.js ao diretório wwwroot.Add a JavaScript file named site.js to the wwwroot directory. Substitua o conteúdo pelo seguinte código:Replace its contents with the following code:

const uri = "api/todo";
let todos = null;
function getCount(data) {
  const el = $("#counter");
  let name = "to-do";
  if (data) {
    if (data > 1) {
      name = "to-dos";
    }
    el.text(data + " " + name);
  } else {
    el.text("No " + name);
  }
}

$(document).ready(function() {
  getData();
});

function getData() {
  $.ajax({
    type: "GET",
    url: uri,
    cache: false,
    success: function(data) {
      const tBody = $("#todos");

      $(tBody).empty();

      getCount(data.length);

      $.each(data, function(key, item) {
        const tr = $("<tr></tr>")
          .append(
            $("<td></td>").append(
              $("<input/>", {
                type: "checkbox",
                disabled: true,
                checked: item.isComplete
              })
            )
          )
          .append($("<td></td>").text(item.name))
          .append(
            $("<td></td>").append(
              $("<button>Edit</button>").on("click", function() {
                editItem(item.id);
              })
            )
          )
          .append(
            $("<td></td>").append(
              $("<button>Delete</button>").on("click", function() {
                deleteItem(item.id);
              })
            )
          );

        tr.appendTo(tBody);
      });

      todos = data;
    }
  });
}

function addItem() {
  const item = {
    name: $("#add-name").val(),
    isComplete: false
  };

  $.ajax({
    type: "POST",
    accepts: "application/json",
    url: uri,
    contentType: "application/json",
    data: JSON.stringify(item),
    error: function(jqXHR, textStatus, errorThrown) {
      alert("Something went wrong!");
    },
    success: function(result) {
      getData();
      $("#add-name").val("");
    }
  });
}

function deleteItem(id) {
  $.ajax({
    url: uri + "/" + id,
    type: "DELETE",
    success: function(result) {
      getData();
    }
  });
}

function editItem(id) {
  $.each(todos, function(key, item) {
    if (item.id === id) {
      $("#edit-name").val(item.name);
      $("#edit-id").val(item.id);
      $("#edit-isComplete")[0].checked = item.isComplete;
    }
  });
  $("#spoiler").css({ display: "block" });
}

$(".my-form").on("submit", function() {
  const item = {
    name: $("#edit-name").val(),
    isComplete: $("#edit-isComplete").is(":checked"),
    id: $("#edit-id").val()
  };

  $.ajax({
    url: uri + "/" + $("#edit-id").val(),
    type: "PUT",
    accepts: "application/json",
    contentType: "application/json",
    data: JSON.stringify(item),
    success: function(result) {
      getData();
    }
  });

  closeInput();
  return false;
});

function closeInput() {
  $("#spoiler").css({ display: "none" });
}

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:A change to the ASP.NET Core project's launch settings may be required to test the HTML page locally:

  • Abra Properties\launchSettings.json.Open Properties\launchSettings.json.
  • Remova a launchUrl propriedade para forçar o aplicativo a abrir em index.html — o arquivo padrão do projeto.Remove the launchUrl property to force the app to open at index.html—the project's default file.

Esta amostra chama todos os métodos CRUD da API Web.This sample calls all of the CRUD methods of the web API. Veja a seguir explicações das chamadas à API.Following are explanations of the calls to the API.

Obter uma lista de itens pendentes 2,1Get a list of to-do items 2.1

o jQuery envia uma solicitação HTTP GET para a API da Web, que retorna JSON representando uma matriz de itens de tarefas pendentes.jQuery sends an HTTP GET request to the web API, which returns JSON representing an array of to-do items. A função de retorno de chamada success será invocada se a solicitação for bem-sucedida.The success callback function is invoked if the request succeeds. No retorno de chamada, o DOM é atualizado com as informações do item pendente.In the callback, the DOM is updated with the to-do information.

$(document).ready(function() {
  getData();
});

function getData() {
  $.ajax({
    type: "GET",
    url: uri,
    cache: false,
    success: function(data) {
      const tBody = $("#todos");

      $(tBody).empty();

      getCount(data.length);

      $.each(data, function(key, item) {
        const tr = $("<tr></tr>")
          .append(
            $("<td></td>").append(
              $("<input/>", {
                type: "checkbox",
                disabled: true,
                checked: item.isComplete
              })
            )
          )
          .append($("<td></td>").text(item.name))
          .append(
            $("<td></td>").append(
              $("<button>Edit</button>").on("click", function() {
                editItem(item.id);
              })
            )
          )
          .append(
            $("<td></td>").append(
              $("<button>Delete</button>").on("click", function() {
                deleteItem(item.id);
              })
            )
          );

        tr.appendTo(tBody);
      });

      todos = data;
    }
  });
}

Adicionar um item pendente 2,1Add a to-do item 2.1

o jQuery envia uma solicitação HTTP POST com o item de tarefas pendentes no corpo da solicitação.jQuery sends an HTTP POST request with the to-do item in the request body. As opções accepts e contentType são definidas como application/json para especificar o tipo de mídia que está sendo recebido e enviado.The accepts and contentType options are set to application/json to specify the media type being received and sent. O item pendente é convertido em JSON usando JSON.stringify.The to-do item is converted to JSON by using JSON.stringify. Quando a API retorna um código de status de êxito, a função getData é invocada para atualizar a tabela HTML.When the API returns a successful status code, the getData function is invoked to update the HTML table.

function addItem() {
  const item = {
    name: $("#add-name").val(),
    isComplete: false
  };

  $.ajax({
    type: "POST",
    accepts: "application/json",
    url: uri,
    contentType: "application/json",
    data: JSON.stringify(item),
    error: function(jqXHR, textStatus, errorThrown) {
      alert("Something went wrong!");
    },
    success: function(result) {
      getData();
      $("#add-name").val("");
    }
  });
}

Atualizar um item de tarefas pendentes 2,1Update a to-do item 2.1

A atualização de um item pendente é semelhante à adição de um.Updating a to-do item is similar to adding one. A url é alterada para adicionar o identificador exclusivo do item, e o type é PUT.The url changes to add the unique identifier of the item, and the type is PUT.

$.ajax({
  url: uri + "/" + $("#edit-id").val(),
  type: "PUT",
  accepts: "application/json",
  contentType: "application/json",
  data: JSON.stringify(item),
  success: function(result) {
    getData();
  }
});

Excluir um item de tarefas pendentes 2,1Delete a to-do item 2.1

A exclusão de um item pendente é feita definindo o type na chamada do AJAX como DELETE e especificando o identificador exclusivo do item na URL.Deleting a to-do item is accomplished by setting the type on the AJAX call to DELETE and specifying the item's unique identifier in the URL.

$.ajax({
  url: uri + "/" + id,
  type: "DELETE",
  success: function(result) {
    getData();
  }
});

Adicionar suporte de autenticação a uma API Web 2,1Add authentication support to a web API 2.1

ASP.NET Core Identity Adiciona a funcionalidade de logon da interface do usuário para ASP.NET Core aplicativos Web.ASP.NET Core Identity adds user interface (UI) login functionality to ASP.NET Core web apps. Para proteger APIs Web e SPAs, use um dos seguintes:To secure web APIs and SPAs, use one of the following:

IdentityServer4 é uma estrutura de OpenID Connect e OAuth 2,0 para ASP.NET Core.IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core. IdentityO Server4 habilita os seguintes recursos de segurança:IdentityServer4 enables the following security features:

  • AaaS (autenticação como serviço)Authentication as a Service (AaaS)
  • Logon único/logoff (SSO) em vários tipos de aplicativosSingle sign-on/off (SSO) over multiple application types
  • Controle de acesso para APIsAccess control for APIs
  • Gateway de FederaçãoFederation Gateway

Para obter mais informações, consulte Bem-vindo ao Identity Server4.For more information, see Welcome to IdentityServer4.

Recursos adicionais 2,1Additional resources 2.1

Exibir ou baixar o código de exemplo para este tutorial.View or download sample code for this tutorial. Consulte como baixar.See how to download.

Para obter mais informações, consulte os seguintes recursos:For more information, see the following resources: