Podpora content negotiation a XML formátu v REST API
Článek se vztahuje k verzi produktu ASP.NET Core 3.0
Tento článek byl napsán v roce 2019. Vývojářské technologie se neustále inovují a článek již nemusí popisovat aktuální stav technologie, ideální řešení a můj současný pohled na dané téma.
Použitelnosti REST API pomáhá podpora různých formátů pro serializaci. Výchozí volbou pro většinu vývojářských týmů je logicky JSON. Z hlediska integrace REST API v historicky starších systémech se však vyplatí přidat také podporu pro XML. To je v ASP.NET Core naštěstí velmi jednoduché.
Výchozí nastavení ASP.NET Core
Rozhodnete-li se postavit si jednoduché REST API v ASP.NET Core MVC, automaticky máte v projektu zajištěnou podporu content negotiation a formátu JSON. V zásadě máte v projektu zapojené:
- Input Formatters - slouží pro deserializaci payloadu
- Output Formatters - slouží pro serializaci objektů do zvoleného formátu
Automatická volba formatteru probíhá na základě HTTP hlaviček. V případě input formatters se zohledňuje request hlavička Content-Type a v případě požadovaného návratového typu hlavička Accept. Pokud HTTP hlavička chybí, použijí se výchozí formattery: SystemTextJsonInputSerializer a SystemTextJsonOutputFormatter.
Status Codes 406 a 415
Výchozí nastavení není správné, protože vytváří prostor pro vznik chyb. Konzument by měl deklarovat, v jakém formátu posílá payload a v jakém formátu chce data vrátit. Pokud nejsme schopni data v REST API přijmout, měli bychom vracet 415 Unsupported Media Type. Jestliže nejsme schopni data emitovat v požadovaném formátu, měli bychom vracet 406 Not Acceptable. Nastavení v ASP.NET Core je jednoduché:
public void ConfigureServices(IServiceCollection services) { var mvc = services.AddControllers(options => { options.ReturnHttpNotAcceptable = true; }); }
JSON Serializer
Od verze ASP.NET Core 3.0 se používá jako výchozí serializer System.Text.Json. Jedná se o nový, výkonnostně optimalizovaný serializer. Ve starších verzích frameworku byla zapojena podpora Newtonsoft.Json. Znamená to, že po migraci na ASP.NET Core 3.0 lze očekávat, že se serializace a deserializace může (a v praxi bude) chovat trochu jinak. Proti tomu můžete bojovat více způsoby:
- Konfigurací nového JsonSerializeru
- Náhradou JsonSerializeru za tradiční Newtonsoft.Json
Konfigurace System.Text.Json
První pokusy můžete věnovat snaze o konfiguraci nového serializeru. Slouží k tomu třída JsonSerializerOptions a můžete ji nastavit buď globálně, nebo lokálně na místě, kde serializaci používáte.
var options = new JsonSerializerOptions { WriteIndented = true, IgnoreNullValues = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, DictionaryKeyPolicy = JsonNamingPolicy.CamelCase }; context.Response.Headers.Add(HeaderNames.ContentType, "application/json"); await JsonSerializer.SerializeAsync(context.Response.Body, payload, options);
Jestliže Vám konfigurace nebude stačit a budete stále bojovat s chováním nového serializeru, dost možná vám dojde trpělivost a nakonec skončíte u druhé možnosti.
Přechod zpět na Newtonsoft.Json
Druhá možnost je vrátit se k Newtonsoft.Json serializeru. Pro tento účel můžeme použít integrační NuGet balíček
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
a následně zapojit serializer pomocí provolání
public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddNewtonsoftJson(options => { // settings }); }
Zapojení podpory XML
Konečně se také dostáváme k tomu, jak lze snadno zapojit podporu XML. Chcete-li přidat hromadně input + output formatter, stačí přidat řádky:
public void ConfigureServices(IServiceCollection services) { var mvc = services.AddControllers(); mvc.AddXmlSerializerFormatters(); }
Alternativně mohu zapojit například jen output formatter. To se hodí pro scénáře, kdy vaše API zpracovává výhradně JSON, ale některé endpointy musí umět vracet ven i XML.
var mvc = services.AddControllers(options => { options.OutputFormatters.Add(new XmlSerializerOutputFormatter()); });