Content Negotiation in .NET Core Web API

Introduction

The process of choosing the best resource for a response when there are several resource representations available is known as content negotiation. Although content negotiation has been a feature of HTTP for some time, it may not be used as much as it could be for various reasons.

To put it briefly, content negotiation allows you to select, or more accurately, "negotiate," the content that is returned in response to a REST API request.

Content negotiation
 

What Is It?

A restriction associated with REST services is that the client must have the ability to select the format in which they would like the response, for example, XML or JSON. We refer to this as content negotiation.

In more detail, a client and server can agree on the format of the data to be exchanged through a mechanism called content negotiation in REST services. Through this procedure, the data format is guaranteed to be comprehensible and agreeable to all parties involved in the communication.

How are Content Negotiations handled?

Accept and Content-Type are the two HTTP headers that are mainly involved in content negotiation.

  1. Accept Header: The client uses this field to indicate the kinds of media that it is ready, willing, and able to handle. To specify whether a client wants to receive data in the XML (application/xml) or JSON (application/json) formats, for example, the client can use the Accept header.
  2. Content-Type Header: The server uses the Content-Type Header to indicate the media type of the response content that it is sending back to the client. It guarantees that the client is capable of parsing and processing the received data by informing them of the format in which the response data is encoded.

ASP.NET Core Web API ignores the browser's Accept header and returns a JSON-formatted result by default.

The following media types are supported by ASP.NET Core by default:

  • application/json
  • text/json
  • text/plain

ASP.NET Core Web API Content Negotiation Implementation

Because of its built-in infrastructure, ASP.NET Core Web API makes the implementation of content negotiation simpler. By configuring custom formatters, the framework can support additional formats in addition to JSON and XML, which are supported out of the box.

  1. Built-in Support: JSON is the main data exchange format for ASP.NET Core Web API projects by default. Formatters in the Program.cs file can be configured to enable XML and other formats.
  2. Custom Formatters: By extending the TextInputFormatter and TextOutputFormatter classes, or their binary equivalents for non-text formats, developers can create custom Formatters to support new content types.
  3. Configuration: Developers can add or configure Formatters in the Program.cs Main method by using the AddMvc or AddControllers methods (for API projects). Here, one can set up custom formatters, configure options, and list supported media types.

The Default JSON Response

Let's now send an HTTP GET Request to the endpoint, instructing it to send the response in JSON format, as seen in the image below, by using the Accept header and setting its value to application/json. Kindly adjust the port number that your application is currently using:

JSON Response

Let's now send a second HTTP GET request to the aforementioned endpoint, setting the Accept header value to application/xml as seen in the image below, and observe the format of the response that we receive.

 HTTP

As seen in the image above, we receive the response in XML format even when we set the Accept header value to application/XML. This is a result of our application's XML formatters not being enabled yet. JSON Formatter is the only formatter that is enabled by default, and it is this formatter that sends the response by default regardless of the value of the Accept header. The value of the Content-Type header is application/XML, even if you inspect the response header.

Return XML Response

Where a server formats a response to JSON is not made clear. However, we can override it by modifying the AddControllers() method's configuration options. It is located in the Program class by default and has the following appearance:

services.builder.AddControllers();

When the client attempts to negotiate for the XML response, we can add the following options to allow the server to format it:

builder.Services.AddControllers(options =>
{
    options.RespectBrowserAcceptHeader = true;
}).AddXmlSerializerFormatters();

Initially, we need to instruct a server to honor the Accept header. The AddXmlSerializerFormatters() method is then added to support XML formatters.

After configuring our server, let's try the content negotiation again.

 Content Negotiation

Our XML response is shown there; it is no longer the default response. We can obtain responses in a different format by modifying the Accept header.

Restricting Media Type in Content Negotiation

As of right now, if the media type is not detected, JSON will be returned as the default response.

However, we can limit this behavior by including the following line in the configuration:

builder.Services.AddControllers(options =>
{
    options.RespectBrowserAcceptHeader = true;
    options.ReturnHttpNotAcceptable = true;

}).AddXmlSerializerFormatters();

We've added the ReturnHttpNotAcceptable = true option, which instructs the server to return the 406 Not Acceptable status code in the event that the client attempts to negotiate for a media type that the server does not support.

As a result, the API consumer will be forced to request only those types that the server supports, increasing the restrictions in your application. For this reason, the 406 status code was developed.

Let's now attempt to retrieve the text/CSV media type using Postman and observe the results.

 Media Type

As anticipated, the response body is absent, leaving us with nothing more than a polite 406 Not Acceptable status code.

We learned the new technique and evolved together.

Happy coding!


Similar Articles