Retornando dado específico  em API REST ASP.NET Core
Tags: braziliandevs, aspnetcore, restapi
Published: 2021-03-21 03:31:28

Existem algumas diferenças entre a rota de listagem de todos os dados e da listagem específica. Entre elas, as duas que se destacam são:
  
* Precisamos receber um parâmetro indicando qual objeto retoranr
* Precisamos verificar se o objeto existe ou não para que seja retornada uma mensagem de erro.

Uma rota para retornar um objeto do tipo `Palavra`, sendo especificado pelo seu `id` recebe a seguinte anotação:
```c#
[HttpGet]
[Route("{id}")]
public async Task Palavra GetPalavra(int id)
{
    ...
}
```

Estamos dizendo pro ASP.NET core que nossa rota irá receber um parâmetro, que estamos chamando de id. Isso pois, caso queiramos retornar a palavra com id 2, iremos realizar uma chamada na rota `/api/Palavras/2`.

No exemplo acima, dizemos então que a rota recebe um atributo chamado id. Esse atributo é passado como argumento do método de nossa rota, nesse caso `int id`. Através dessa variável, podemos realizar diversas ações específica a essa rota. No código abaixo, vemos um exemplo simples de retornar uma Palavra por id.
```c#
[HttpGet]
[Route("{id}")]
public async Task ActionResult<Palavra> GetPalavra(int id)
{
    try 
    {
        var palavra = await _repository.GetPalavraPorId(id);
        return palavra;
    }
    catch (Exception)
    {
        return this.StatusCode(StatusCodes.Status500InternalServerError, "Database failure");
    }
   
}
```
## Retornando Not Found
O código acima possuí um problema. No caso de não haver uma palavra com o `id` recebido, é retornado o código HTTP 204: No Content

![Erro 204 no content](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yio7r9i3z7cfts2ce09t.png)
 
O correto seria retornar uma mensagem de erro para o cliente, com o retorno `404 Not Found`. Sabemos que existe um método que retorna esse erro, o `NotFoun()`, basta então checarmos no controller se o retorno do banco está vazio ou não

```c#
[HttpGet]
[Route("{id}")]
public async Task ActionResult<Palavra> GetPalavra(int id)
{
    try 
    {
        var palavra = await _repository.GetPalavraPorId(id);
        if (palavra == null) return NotFound();
        return palavra;
    }
    catch (Exception)
    {
        return this.StatusCode(StatusCodes.Status500InternalServerError, "Database failure");
    }
   
}
```

Nosso código agora, irá retornar o erro 404 caso a Palavra não seja encontrada no banco de dados, junto de um JSON que segue a RFC 7807.
```json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  "title": "Not Found",
  "status": 404,
  "traceId": "|6b16da39-47c24449f9eb6854."
}
```

E, como antes, no caso do método ser executado com sucesso, é retornado nosso objeto em JSON com o código HTTP 200: OK.

## Exceptions
Uma boa prática de quando acontecer uma exception é realizar um log dela e retornar um erro 500. Para isso, capturamos a exception e escrevemos no log. Isso pode ser feito tanto no `catch` quanto em um [filtro que captura exceptions](https://docs.microsoft.com/pt-br/aspnet/core/mvc/controllers/filters?view=aspnetcore-5.0#exception-filters).

O cliente então irá receber um código 500 caso ocorra algum erro interno. Se formos lançar essa exception, a aplicação irá ser suspendida, o que não seria uma boa ideia. Exceptions podem ser erros como um banco de dados indisponível, onde não temos controler por ser algo inesperado.

# Fontes
https://docs.microsoft.com/pt-br/aspnet/core/mvc/controllers/routing?view=aspnetcore-5.0#ar
http://www.macoratti.net/19/06/aspnc_3dwebapi1.htm
https://docs.microsoft.com/pt-br/aspnet/core/mvc/controllers/filters?view=aspnetcore-5.0#exception-filters