Při práci s aplikačním rozhraním preferuji formát JSON pro jeho srozumitelnost a úspornost. Přesto se občas hodí mít API nastavené i pro podporu formátu XML a plně tak podporovat content negotiation dle požadovaného typu.
Tento článek doplňuje superdlouhý článek RESTful API Design, který jsem napsal na svém blogu a který doporučuji přečíst.
Podpora agent drivent content negotiation vypadá tak, že ze strany agenta je přijímána HTTP header:
Accept: text/xml
nebo pro JSON například:
Accept: text/json
Webový server pak obvykle (pokud tento formát podporuje) odpovídá odpovídajícím contentem s HTTP hlavičkou:
Content-Type: text/json; charset=utf-8
Formatter config
Prvním krokem k nastavení podpory XML je nastavení XML formatteru. Ve Web API projektu mám všechny formatters pohromadě volané z global.asax aplikačního rozhraní.
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// other code
FormatterConfig.RegisterFormatters(GlobalConfiguration.Configuration.Formatters);
}
}
Nicméně není problém přistoupit k nastavení odkudkoliv přímo
var formatters = GlobalConfiguration.Configuration.Formatters;
Pro XML serializer lze použít následující nastavení:
public class FormatterConfig
{
public static void RegisterFormatters(MediaTypeFormatterCollection formatters)
{
formatters.Add(new XmlMediaTypeFormatter());
formatters.XmlFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
formatters.XmlFormatter.UseXmlSerializer = true;
}
}
- Přidáme nový formatter pro XML
- Přidáme podporovaný typ (to je value uvedena v HTTP hlavičce Accept)
- Explicitně si vyžádáme použití XmlSerializeru
Format text/xml VS. application/xml
Rozdíl z hlediska MIME typu (a netýká se jen XML ale i JSONu) popisují různé RFC. V případě XML je to RFC 3023. Dle bodu 3:
Pokud je XML dokument nezpracovaný (zdrojový XML) a čitelný pro běžné uživatele, pak upřednostňujeme text/xml před application/xml. Naopak application/xml dáváme přednost všude tam, kde není XML čitelný pro běžné uživatele.
Tato definice je nicméně dost nejasná (hlavně kvůli pojmu (ne)čitelný) pro běžné uživatele. Jsem zastáncem toho, že XML dokument by měl být ideálně čitelný vždy a doporučil bych použít plain formát text/xml
.
XmlSerializer
Standardně používá Web API vlastní serializer. Ten má celou řadu nešvarů, například v podobě generování ošklivých namespaces. Také se mi nezřídka stávalo, že nebyl schopen některé entity serializovat. Proto je lepší použít "standardní" XmlSerializer místo DataContractSerializeru. To lze provést nastavením:
formatters.XmlFormatter.UseXmlSerializer = true;
XmlSerializer umí serializovat objekty do XML a stejně tak zpětně deserializovat XML do objektů na základě definované struktury tříd.
Serializace
Proces serializace spočívá jen v přípravě tříd pro serializaci. K tomu je vhodné použít data anotace, které jsou ve jmenném prostoru System.Runtime.Serialization
.
Příklad objektu pro serializaci:
[DataContract(Namespace = "")]
public class Article
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string Description { get; set; }
}
Pro Web API doporučuji používat [DataContract(Namespace = "")]
, aby se zamezilo generování jmenných prostorů do XML. Atributů pro popsání serializace je celá řada.
Serializovat data lze i přímo v kódu:
var serializer = new XmlSerializer(typeof (T));
serializer.Serialize(@"c:/output.xml", new Article());
Deserializace
Deserializace je proces, kde již více záleží na přesnosti. Je nutné aby přesně souhlasily názvy properties a elementů XML dokumentu. Při parsování lze však používat vlastní názvy properties odekorované o anotace popisující přesné názvy elementů. Pokud tedy chceme použít API pro zpracování dat třetí strany, často budeme potřebovat další anotace.
[XmlType(TypeName = "PRODUCT")]
public class Product
{
private double? price?
[XmlElement("PRODUCTNAME")]
public string Title { get; set; }
[XmlElement("PRICESPECIAL")]
public double? Price
{
get
{
if (!price.HasValue)
return null;
return Math.Round(price.Value, 2);
}
set
{
if (!value.HasValue)
price = null;
price = value;
}
}
}
Závěr
XML stále patří mezi dva velmi významné formáty a vzhledem k snadnému nastavení Web API sle vyplatí podporovat content negotiation. Na druhou stranu u větších projektů, kde není přímá potřeba s XML formátem pracovat může být popisování struktury entit anotacemi nevyužitá práce navíc.
Velkou výhodou content negotiation API je možnost zpracovávat požadavky služeb třetích stran. Požadavky pak není nutné složitě parsovat nebo procházet pomocí XmlDocument ale pouze si vytvořit korespondující datové objekty a nechat na XmlSerializeru proces deserializace bez jakéhokoliv úsilí.
Zdroje
Přednáška Web API
O základních principech Web API budu mluvit na přednášce v Hradci Králové:
5. 11. 2014 17:00 – První středa na FIM UHK – Web API