Negociação de conteúdo e formatters
ResumoContent negotiation permite que o cliente peça o formato da resposta pelo cabeçalho
Accept(ex.: JSON ou XML). Configuramos os formatters e vemos como restringir tipos de mídia e criar um formatter customizado.
1. Objetivos de Aprendizagem#
- Entender o que a API oferece "out of the box" na negociação de conteúdo.
- Habilitar formatters adicionais (ex.: XML) e restringir media types.
- Esboçar um output formatter customizado.
2. Pré-requisitos#
- Endpoints GET retornando DTOs (Módulo 18).
3. Conceito#
Content negotiation é o processo pelo qual servidor e cliente concordam sobre o formato da resposta, usando o cabeçalho Accept da requisição. Por padrão, o ASP.NET Core responde em JSON (System.Text.Json). O porquê de suportar mais: interoperabilidade com clientes que exigem outros formatos.
Peças-chave:
RespectBrowserAcceptHeader— respeita oAcceptdo navegador.ReturnHttpNotAcceptable— retorna406 Not Acceptablese nenhum formatter atende.- Output formatters — convertem o objeto em bytes no formato pedido.
4. Mão na Massa#
4.1. Setup#
Para XML:
# incluso no framework; basta habilitar AddXmlDataContractSerializerFormatters()
4.2. Implementação Passo a Passo#
- Configure os formatters:
builder.Services.AddControllers(config =>
{
config.RespectBrowserAcceptHeader = true;
config.ReturnHttpNotAcceptable = true; // 406 quando o formato não é suportado
})
.AddXmlDataContractSerializerFormatters(); // habilita XML
- Teste pedindo XML:
curl -H "Accept: application/xml" http://localhost:5000/api/categorias
- Restringir media types em um controller/ação:
[Produces("application/json")]
[HttpGet]
public IActionResult Get() => Ok();
4.3. Executando#
Accept: application/json→ JSON.Accept: application/xml→ XML (se habilitado).Accept: text/csvsem formatter e comReturnHttpNotAcceptable=true→406.
5. Exemplo Completo#
Esboço de um output formatter customizado (CSV):
public class CsvOutputFormatter : TextOutputFormatter
{
public CsvOutputFormatter()
{
SupportedMediaTypes.Add(new("text/csv"));
SupportedEncodings.Add(System.Text.Encoding.UTF8);
}
protected override bool CanWriteType(Type? type) =>
typeof(IEnumerable<CategoriaDto>).IsAssignableFrom(type) ||
typeof(CategoriaDto).IsAssignableFrom(type);
public override async Task WriteResponseBodyAsync(
OutputFormatterWriteContext context, System.Text.Encoding encoding)
{
var buffer = new System.Text.StringBuilder();
if (context.Object is IEnumerable<CategoriaDto> lista)
foreach (var c in lista) buffer.AppendLine($"{c.Id},{c.Nome}");
else if (context.Object is CategoriaDto c)
buffer.AppendLine($"{c.Id},{c.Nome}");
await context.HttpContext.Response.WriteAsync(buffer.ToString());
}
}
Registro: config.OutputFormatters.Add(new CsvOutputFormatter());
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
Ativar ReturnHttpNotAcceptable para respostas HTTP corretas | Devolver JSON silenciosamente quando o cliente pediu outro formato |
Restringir media types com [Produces]/[Consumes] | Aceitar qualquer formato sem controle |
| Só adicionar formatters que você realmente suporta | Prometer formatos sem implementação |
Atençãoo serializador XML (
DataContractSerializer) não lida bem comrecordsposicionais ou tipos sem construtor sem parâmetros. Ajuste os DTOs se for oferecer XML.
7. Segurança e Produção#
- Formatters customizados que serializam objetos arbitrários podem vazar campos; controle o que é escrito explicitamente.
8. Exercícios#
- Fácil: habilite XML e confirme o
406para um formato não suportado. - Médio: aplique
[Produces("application/json")]a um controller e observe o efeito na negociação. - Desafio: finalize o
CsvOutputFormattere teste comAccept: text/csv.
9. Resumo#
Content negotiation deixa o cliente escolher o formato via Accept. Configuramos formatters, retornamos 406 quando apropriado e esboçamos um formatter customizado.
10. Próximos Passos#
Módulo 22: propriedades de segurança e idempotência dos métodos HTTP.
11. Referências#
- Microsoft Learn — Formatar dados de resposta / content negotiation
- Microsoft Learn — Formatters customizados
- Microsoft Learn — System.Text.Json