Durante o mês de setembro/2018, foi disponibilizado o Preview 2 do ASP.NET Core 2.2, com o anúncio oficial acontecendo juntamente com as versões 2.2 do .NET Core e do Entity Framework Core durante o .NET Conf 2018.
Informações sobre estes releases podem ser encontradas nos seguintes artigos:
- Announcing .NET Core 2.2 Preview 2
- ASP.NET Core 2.2.0-preview2 now available
- Announcing Entity Framework Core 2.2 Preview 2 and the preview of the Cosmos DB provider and spatial extensions for EF Core
Este primeiro artigo marca o início de uma série que produzirei sobre as novidades do ASP.NET Core 2.2. Além de orientações para a instalação do Preview 2, abordarei ainda o uso de API Conventions como meio para facilitar a documentação de APIs REST em conjunto com o Swagger.
Instalando o Preview 2 do .NET Core 2.2 e do Visual Studio 2017 15.9
Para iniciar a utilização do ASP.NET Core 2.2, será necessário proceder com a instalação do SDK do Preview 2 do .NET Core 2.2. Compatível com Windows, diversas distribuições Linux e macOS, o instalador do .NET Core 2.2 está disponível através do seguinte link:
A imagem a seguir traz o resultado da execução do comando dotnet –version, com a mesma indicando que o Preview 2 foi implantado com sucesso:
Atualmente o Preview 2 do release 15.9.0 do Visual Studio 2017 possui suporte ao ASP.NET Core 2.2. Esta versão pode ser obtida a partir do próprio instalador da IDE:
Caso todo este processo tenha ocorrido sem maiores dificuldades, no Visual Studio será possível observar como opção os templates para a versão 2.2 do ASP.NET Core:
API Conventions
Uma prática bastante comum ao se empregar o Swagger na documentação de APIs REST com o ASP.NET Core está no uso do atributo ProducesResponseType, o qual permite indicar os prováveis retornos de uma Action. Na listagem a seguir temos um Controller (classe CatalogoContext) que exemplifica esta técnica:
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Swagger;
namespace APICatalogo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CatalogoController : ControllerBase
{
private CatalogoContext _contexto;
public CatalogoController(CatalogoContext context)
{
_contexto = context;
}
[HttpGet("produtos/{codigo}")]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(Produto), (int)HttpStatusCode.OK)]
public ActionResult<Produto> GetProduto(string codigo)
{
Produto prod = null;
if (codigo.StartsWith("PROD"))
prod = _contexto.ObterItem<Produto>(codigo);
if (prod != null)
return prod;
else
return NotFound();
}
[HttpGet("servicos/{codigo}")]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(Servico), (int)HttpStatusCode.OK)]
public ActionResult<Servico> GetServico(string codigo)
{
Servico serv = null;
if (codigo.StartsWith("SERV"))
serv = _contexto.ObterItem<Servico>(codigo);
if (serv != null)
return serv;
else
return NotFound();
}
}
}
O ASP.NET Core 2.2 conta agora com as API Conventions. Trata-se, na prática, de um conjunto de convenções que podem ser empregadas ao invés do atributo ProducesResponseType, simplificando assim o processo de documentação de uma API e contribuindo ainda para um código mais enxuto.
A próxima listagem traz este primeiro exemplo modificado, de forma a utilizar atributo ApiConventionMethod nas diferentes Actions do Controller:
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Swagger;
namespace APICatalogo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CatalogoController : ControllerBase
{
private CatalogoContext _contexto;
public CatalogoController(CatalogoContext context)
{
_contexto = context;
}
[HttpGet("produtos/{codigo}")]
[ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Get))]
public ActionResult<Produto> GetProduto(string codigo)
{
Produto prod = null;
if (codigo.StartsWith("PROD"))
prod = _contexto.ObterItem<Produto>(codigo);
if (prod != null)
return prod;
else
return NotFound();
}
[HttpGet("servicos/{codigo}")]
[ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Get))]
public ActionResult<Servico> GetServico(string codigo)
{
Servico serv = null;
if (codigo.StartsWith("SERV"))
serv = _contexto.ObterItem<Servico>(codigo);
if (serv != null)
return serv;
else
return NotFound();
}
}
}
Ao analisar o resultado gerado pelo Swagger, será possível observar como retornos possíveis os códigos HTTP 200 (OK) e 404 (Not Found):
Este mesmo tipo de comportamento pode ser aplicado a um Controller através do atributo ApiConventionType, o qual receberá como parâmetro o tipo DefaultApiConventions:
using Microsoft.AspNetCore.Mvc;
namespace APICatalogo.Controllers
{
[ApiConventionType(typeof(DefaultApiConventions))]
[Route("api/[controller]")]
[ApiController]
public class ProdutosController : ControllerBase
{
private CatalogoContext _contexto;
public ProdutosController(CatalogoContext context)
{
_contexto = context;
}
[HttpGet("{id}")]
public ActionResult<Produto> Get(string id)
{
Produto prod = null;
if (id.StartsWith("PROD"))
prod = _contexto.ObterItem<Produto>(id);
if (prod != null)
return prod;
else
return NotFound();
}
}
}
Ou ainda a todo um projeto combinando a utilização de ApiConventionType e DefaultApiConventions com o atributo assembly:
using Microsoft.AspNetCore.Mvc;
[assembly: ApiConventionType(typeof(DefaultApiConventions))]
namespace APICatalogo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ProdutosController : ControllerBase
{
private CatalogoContext _contexto;
public ProdutosController(CatalogoContext context)
{
_contexto = context;
}
[HttpGet("{id}")]
public ActionResult<Produto> Get(string id)
{
Produto prod = null;
if (id.StartsWith("PROD"))
prod = _contexto.ObterItem<Produto>(id);
if (prod != null)
return prod;
else
return NotFound();
}
}
}