Introdução
No mundo do desenvolvimento de software, a criação de APIs RESTful se tornou uma prática essencial, permitindo que diferentes aplicações se comuniquem de forma eficiente. Neste tutorial, vamos explorar o processo de desenvolvimento de uma API RESTful utilizando C# e ASP.NET Core. Vamos usar o Swagger para fornecer documentação automática, facilitando a interação com a API e permitindo que os desenvolvedores entendam rapidamente como utilizá-la. Também utilizaremos o AutoMapper, uma biblioteca que simplifica o mapeamento entre diferentes objetos, o que é extremamente útil quando trabalhamos com modelos de dados e DTOs (Data Transfer Objects). Por meio deste guia prático, você adquirirá conhecimento passo a passo sobre como criar uma API robusta, efetuar o mapeamento de dados e garantir que a documentação esteja sempre atualizada, proporcionando uma experiência perfeita tanto para os desenvolvedores quanto para os usuários finais.
Etapas
Configuração do Ambiente de Desenvolvimento
Para começar, você deve ter o .NET SDK instalado. Você pode baixá-lo no site oficial da Microsoft. Após a instalação, verifique se tudo está instalado corretamente usando o seguinte comando no terminal:
commands# Verificar se o .NET SDK está instalado
dotnet --versionCriação do Projeto ASP.NET Core
Usando o terminal, navegue até o diretório onde deseja criar o projeto e execute o seguinte comando para criar uma nova API ASP.NET Core:
commands# Criar um novo projeto API
dotnet new webapi -n MyApi
cd MyApiInstalação do Swagger
Para adicionar o Swagger ao seu projeto, abra o arquivo `MyApi.csproj` e adicione a dependência do Swagger. Alternativamente, você pode usar o comando a seguir:
commandsdotnet add package Swashbuckle.AspNetCore
Configuração do Swagger no `Startup.cs`
Para habilitar o Swagger, você precisa modificar a classe `Startup`. No método `ConfigureServices`, adicione a linha para adicionar os serviços do Swagger. Em seguida, no método `Configure`, adicione a middleware do Swagger:
Startup.cspublic void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "MyApi", Version = "v1" }); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyApi v1"); }); }
Criação do Modelo `Produto`
Crie uma pasta chamada `Models` e dentro dela, crie uma classe `Produto` que represente o modelo de dados:
Produto.csnamespace MyApi.Models { public class Produto { public int Id { get; set; } public string Nome { get; set; } public decimal Preco { get; set; } } }
Criação do Repositório `IProdutoRepository`
Crie uma interface `IProdutoRepository` na pasta `Repositories` que definirá os métodos CRUD:
IProdutoRepository.csusing System.Collections.Generic; using System.Threading.Tasks; using MyApi.Models; namespace MyApi.Repositories { public interface IProdutoRepository { Task<IEnumerable<Produto>> GetAllProdutosAsync(); Task<Produto> GetProdutoByIdAsync(int id); Task<Produto> CreateProdutoAsync(Produto produto); Task UpdateProdutoAsync(Produto produto); Task DeleteProdutoAsync(int id); } }
Implementação do Repositório `ProdutoRepository`
Implemente a classe `ProdutoRepository`, que implementa a interface criada anteriormente:
ProdutoRepository.csusing System.Collections.Generic; using System.Threading.Tasks; using MyApi.Models; namespace MyApi.Repositories { public class ProdutoRepository : IProdutoRepository { private static List<Produto> produtos = new List<Produto>(); public async Task<IEnumerable<Produto>> GetAllProdutosAsync() { return await Task.FromResult(produtos); } public async Task<Produto> GetProdutoByIdAsync(int id) { var produto = produtos.Find(p => p.Id == id); return await Task.FromResult(produto); } public async Task<Produto> CreateProdutoAsync(Produto produto) { produto.Id = produtos.Count + 1; produtos.Add(produto); return await Task.FromResult(produto); } public async Task UpdateProdutoAsync(Produto produto) { var existingProduto = produtos.Find(p => p.Id == produto.Id); if (existingProduto != null) { existingProduto.Nome = produto.Nome; existingProduto.Preco = produto.Preco; } } public async Task DeleteProdutoAsync(int id) { var produto = produtos.Find(p => p.Id == id); if (produto != null) { produtos.Remove(produto); } } } }
Criação do Controlador `ProdutoController`
Crie uma classe chamada `ProdutoController` na pasta `Controllers`, que utilizará o repositório para expor os endpoints da API:
ProdutoController.csusing Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.Threading.Tasks; using MyApi.Models; using MyApi.Repositories; namespace MyApi.Controllers { [Route("api/[controller]")] [ApiController] public class ProdutoController : ControllerBase { private readonly IProdutoRepository _produtoRepository; public ProdutoController(IProdutoRepository produtoRepository) { _produtoRepository = produtoRepository; } [HttpGet] public async Task<ActionResult<IEnumerable<Produto>>> GetAllProdutos() { return Ok(await _produtoRepository.GetAllProdutosAsync()); } [HttpGet("{id}")] public async Task<ActionResult<Produto>> GetProduto(int id) { var produto = await _produtoRepository.GetProdutoByIdAsync(id); if (produto == null) return NotFound(); return Ok(produto); } [HttpPost] public async Task<ActionResult<Produto>> CreateProduto(Produto produto) { var createdProduto = await _produtoRepository.CreateProdutoAsync(produto); return CreatedAtAction(nameof(GetProduto), new { id = createdProduto.Id }, createdProduto); } [HttpPut] public async Task<IActionResult> UpdateProduto(int id, Produto produto) { if (id != produto.Id) return BadRequest(); await _produtoRepository.UpdateProdutoAsync(produto); return NoContent(); } [HttpDelete("{id}")] public async Task<IActionResult> DeleteProduto(int id) { await _produtoRepository.DeleteProdutoAsync(id); return NoContent(); } } }
Adicionando o AutoMapper para Mapeamento de Objetos
Para simplificar o mapeamento de objetos, adicione a biblioteca AutoMapper ao seu projeto com o seguinte comando:
commandsdotnet add package AutoMapper
dotnet add package AutoMapper.Extensions.Microsoft.DependencyInjectionConfiguração do AutoMapper
Crie uma classe de perfil para configurar os mapeamentos entre as entidades e os DTOs. Crie uma pasta chamada `Profiles` e dentro dela, crie a classe `MappingProfile`:
MappingProfile.csusing AutoMapper; using MyApi.Models; namespace MyApi.Profiles { public class MappingProfile : Profile { public MappingProfile() { CreateMap<Produto, ProdutoDto>().ReverseMap(); } } }
Criação dos DTOs
Crie uma classe DTO para o modelo `Produto`, chamada `ProdutoDto`, que será utilizada na comunicação com o cliente:
ProdutoDto.csnamespace MyApi.Models { public class ProdutoDto { public string Nome { get; set; } public decimal Preco { get; set; } } }
Implementação de Testes Unitários com xUnit
Para criar testes unitários, adicione o pacote xUnit ao seu projeto com o comando abaixo:
commandsdotnet add package xunit
dotnet add package xunit.runner.visualstudioExemplo de Testes Unitários para `ProdutoController`
Crie uma nova classe chamada `ProdutoControllerTests` e escreva testes para validar os métodos do controlador:
ProdutoControllerTests.csusing Microsoft.AspNetCore.Mvc; using Moq; using System.Collections.Generic; using System.Threading.Tasks; using Xunit; using MyApi.Controllers; using MyApi.Models; using MyApi.Repositories; namespace MyApi.Tests { public class ProdutoControllerTests { private readonly Mock<IProdutoRepository> _mockRepo; private readonly ProdutoController _controller; public ProdutoControllerTests() { _mockRepo = new Mock<IProdutoRepository>(); _controller = new ProdutoController(_mockRepo.Object); } [Fact] public async Task GetAllProdutos_ReturnsOkResult() { // Arrange _mockRepo.Setup(repo => repo.GetAllProdutosAsync()).ReturnsAsync(new List<Produto>()); // Act var result = await _controller.GetAllProdutos(); // Assert var okResult = Assert.IsType<OkObjectResult>(result.Result); Assert.IsType<List<Produto>>(okResult.Value); } } }
Executando a Aplicação e Testes
Compilar e executar o projeto e testar os endpoints utilizando ferramentas como Postman ou cURL.
commands# Compilar e executar a aplicação
dotnet run
# Executar os testes
dotnet testcurl_examples# Listar todos os produtos
curl -X GET https://localhost:5001/api/produtos
# Criar um novo produto
curl -X POST -H "Content-Type: application/json" -d '{"nome":"Novo Produto", "preco":99.99}' https://localhost:5001/api/produtosAcessando a Documentação do Swagger
Após executar a aplicação, você pode acessar a documentação do Swagger em `https://localhost:5001/swagger` para interagir visualmente com sua API.
commandsabrir navegador e acessar https://localhost:5001/swagger
Conclusão
Neste tutorial, você aprendeu a desenvolver uma API RESTful robusta utilizando C# e ASP.NET Core, incluindo como configurar o Swagger para documentação automática e o AutoMapper para simplificação do mapeamento de objetos. Exploramos todo o ciclo de desenvolvimento, desde a criação do projeto até a implementação de testes unitários, proporcionando uma base sólida para futuros projetos. Com essas práticas, você poderá desenvolver APIs eficientes e documentadas, facilitando a integração com outras aplicações e serviços. Essa experiência agrega valor às suas habilidades no desenvolvimento de APIs e contribui significativamente para suas futuras empreitadas no mundo do software.