How to bypass Episerver's Content Delivery API when doing Ajax requests

Published on in C#, Episerver and JavaScript

Requests with the Accept header set to application/json are automatically routed to Content Delivery API. Here's how to bypass it and make the request go to a page controller instead.

Starting from Content Delivery API version 2.3.0, requests with the Accept header set to application/json are automatically routed to Content Delivery API. This is called "Using friendly URLs" in the documentation.

This is a nice feature. But what if you want to make an Ajax request to a page controller instead? For example, if you have a Single Page Application, you might want to retrieve the next page's data in JSON format from the page type's controller using an Ajax request.

In the controller you can do something like this:

public class MyPageController : PageController<MyPage>
{
    public ActionResult Index(MyPage currentPage)
    {
        if (Request.IsAjaxRequest())
        {
            var data = /* ... */;
            return Json(data);
        }

        return View("Index", new MyPageViewModel(currentPage));
    }
}

But, because the Ajax request's Accept header will be set to application/json, the request will be automatically routed to Content Delivery API, and the request will never reach the controller.

The value of the Accept header can't be changed to another MIME type if the desired format for the response data is JSON. So what to do?

Turns out that it's possible to specify a relative quality value for the MIME type: application/json;q=1. From MDN:

Quality values, or q-values and q-factors, are used to describe the order of priority of values in a comma-separated list. It is a special syntax allowed in some HTTP headers and in HTML. The importance of a value is marked by the suffix ';q=' immediately followed by a value between 0 and 1 included, with up to three decimal digits, the highest value denoting the highest priority. When not present, the default value is 1.

Now that the value of the Accept header doesn't strictly equal to application/json, the request is not routed to Content Delivery API. Instead, it reaches the controller. Egg-cellent!

Since only one MIME type is specified, and since the default quality value is anyway 1, appending ;q=1 to the Accept header's value doesn't have any side effects.

You should probably document this somewhere. For example, if you are using fetch(), you can write something like this:

function getPageData(url) {
  return fetch(url, {
    headers: {
      // Requests with the `Accept` header set to `application/json`
      // are automatically routed to Content Delivery API.
      // The `;q=1` here is a "relative quality value"
      // and doesn't have any effects other than
      // tricking the request to go to the controller
      // instead of Content Delivery API.
      Accept: 'application/json;q=1',
    },
  }).then((response) => response.json())
}

This way some overly enthusiastic developer won't remove the quality value thinking that it's unnecessary (since there's only one MIME type and since the default quality value is anyway 1).