ASP.NET Core Web API - Tratamento de erros - II
Neste artigo vamos apresentar uma abordagem de tratamento de erros que pode ser usada em aplicações ASP .NET Core Web API. |
Continuando a primeira parte do artigo veremos como customizar o tratamento de erros de forma mais estruturada.
A abordagem de construir objetos anônimos em tempo real, embora funcione, não é a mais indicada se desejamos ter um projeto robusto.
Para ter um tratamento de erros mais consistente nossa WEb API deve retornar a mesma estrutura de resposta em todos os casos, incluindo os casos de requisição mal sucedidas.
Vejamos um exemplo de implementação usando esta abordagem.
Customizando o tratamento de erros
Em seu projeto WEb API crie uma pasta onde vamos implementar 3 classes para estruturar de forma mais consistente o tratamento de erros. Eu vou criar uma pasta chamada Utils.
Nesta pasta crie uma classe chamada ApiResponse ou outro nome a seu gosto:
using Newtonsoft.Json;
namespace ProdutosApi.Utils
{
public class ApiResponse
{
public int StatusCode { get; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Message { get; }
public ApiResponse(int statusCode, string message = null)
{
StatusCode = statusCode;
Message = message ?? GetDefaultMessageForStatusCode(statusCode);
}
private static string GetDefaultMessageForStatusCode(int statusCode)
{
switch (statusCode)
{
...
case 401:
return "Não autorizado (não autenticado)";
case 404:
return "Recurso não encontrado";
case 405:
return "Método não permitido";
case 500:
return "Um erro não tratado ocorreu no request";
default:
return null;
}
}
}
}
|
Esta classe apresenta duas propriedades e um método :
Agora vamos definir outra classe chamada ApiOkResponse que herda desta classe e que trata as repostas com sucesso:
namespace ProdutosApi.Utils
{
public class ApiOkResponse : ApiResponse
{
public object Result { get; }
public ApiOkResponse(object result)
: base(200)
{
Result = result;
}
}
}
|
Essa classe trata das mensagens para status code 200 que indica uma requisição bem sucedida.
Agora para usar basta definir a chamada no controlador conforme o erro esperado.
Como exemplo para o método HttpDelete onde passamos um id para deletar o produto podemos fazer assim:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduto(int id)
{
var produto = await _ctx.Produtos.FindAsync(id);
if (produto == null)
{
return NotFound(new ApiResponse(404, $"Produto não encontrado.( id ={id}) "));
}
_ctx.Produtos.Remove(produto);
await _ctx.SaveChangesAsync();
return Ok(new ApiOkResponse(produto));
}
|
Fazendo uma requisição POST usando o Postman, para deletar um produto id inexistente temos o resultado abaixo:
Agora testando para excluir um produto existente temos o resultado abaixo:
Bem mais estruturado !!!
Para otimizar o código em nosso projeto podemos criar um filtro Action para reduzir o código usado nas Actions e evitar duplicar código.
Nota: Para detalhes em como usar os Filters veja o meu artigo aqui.
Crie uma classe chamada ApiValidationFilterAttribute na pasta Utils que herda de ActionFilterAttribute e define o código abaixo:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace ProdutosApi.Utils
{
public class ApiValidationFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(new ApiBadRequestResponse(context.ModelState)));
}
base.OnActionExecuting(context);
}
}
}
|
Precisamos agora criar a classe ApiBadRequestResponse na pasta Utils com o código abaixo:
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ProdutosApi.Utils
{
public class ApiBadRequestResponse : ApiResponse
{
public IEnumerable<string> Errors { get; }
public ApiBadRequestResponse(ModelStateDictionary modelState)
: base(400)
{
if (modelState.IsValid)
{
throw new ArgumentException("ModelState deve ser inválido", nameof(modelState));
}
Errors = modelState.SelectMany(x => x.Value.Errors)
.Select(x => x.ErrorMessage).ToArray();
}
}
}
|
Temos agora um tratamento de erro mais eficiente e centralizado.
Existem outras abordagens para este tema mas vamos tratar disso em outro artigo.
"Qual é
mais fácil? Dizer ao paralítico: Estão perdoados os teus pecados, ou dizer:
Levanta-te, toma o teu leito e anda?
Ora, para que saibais que o Filho do Homem tem sobre a terra autoridade para
perdoar pecados — disse ao paralítico: Eu te mando: Levanta-te, toma o teu
leito e vai para tua casa."
Marcos 2:9-11
Veja os
Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique
e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
Quer aprender os conceitos da Programação Orientada a objetos ? Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ? Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ? |
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
Super DVD C# - Recursos de aprendizagens e vídeo aulas para C#
ASP .NET Core 2 - MiniCurso Básico - Macoratti
ASP .NET Core - Macoratti
Conceitos - .NET Framework versus .NET Core - Macoratti
ASP .NET Core - Conceitos Básicos - Macoratti.net
ASP .NET Core MVC - CRUD básico com ADO .NET - Macoratti
ASP .NET Core - Implementando a segurança com ... - Macoratti.net
ASP .NET Core - Apresentando Razor Pages - Macoratti