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 between0
and1
included, with up to three decimal digits, the highest value denoting the highest priority. When not present, the default value is1
.
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
).