Read more

AngularJS: How to force Content-Type on GET and DELETE requests

Arne Hartherz
October 29, 2015Software engineer at makandra GmbH

While you usually do not need a Content-Type on GET request (which have a blank body), an external API may still force you to send one.
Angular's $http service will strip that header Show archive.org snapshot when the request data (body) is blank. [1] This is possibly a misconception of RFC2616 Show archive.org snapshot .

Illustration web development

Do you need DevOps-experts?

Your development team has a full backlog? No time for infrastructure architecture? Our DevOps team is ready to support you!

  • We build reliable cloud solutions with Infrastructure as code
  • We are experts in security, Linux and databases
  • We support your dev team to perform
Read more Show archive.org snapshot

Here is how to send GET requests with a Content-Type header in Angular.

Example

Consider this request:

$http({ method: 'GET', url: '/foobar', headers: { 'Content-Type': 'application/json' } })

Here are the headers of the resulting request:

Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Connection:keep-alive
Host:localhost
User-Agent:(...)

No Content-Type. :(

Solution

One way to fix this is intercepting the request before it is sent, and explicitly setting the Content-Type header.

We chose to do that whenever an X-Force-Content-Type header is set on an outgoing request.
This enables us to set the header only when we want to, not on every request.

Angular allows decorating internal methods, so you can realize this by decorating its $httpBackend. Here a CoffeeScript [2] solution:

@app.decorator '$httpBackend', ['$delegate', ($delegate) ->
  ->
    headers = arguments[4]

    contentType = headers?['X-Force-Content-Type']
    headers['Content-Type'] ?= contentType if contentType?

    $delegate(arguments...)
]

Let's try the example above again (remember to use our new header name):

$http({ method: 'GET', url: '/foobar', headers: { 'X-Force-Content-Type': 'application/json' } })

^
Accept:application/json, text/plain, /
Accept-Encoding:gzip, deflate, sdch
Connection:keep-alive
Content-Type:application/json
Host:localhost
User-Agent:(...)
X-Force-Content-Type:application/json

Yay. :)


[1] The problem is even worse when using Restangular which itself does not even allow passing a body because of its internal logic (also when using customGET). You'd need to modify Restangular which you probably don't want to.

[2] If you don't speak CoffeeScript, take this JavaScript:

this.app.decorator('$httpBackend', ['$delegate', function($delegate) {
  return function() {
    var headers = arguments[4];
    var contentType = (headers != null ? headers['X-Force-Content-Type'] : void 0);
    if (contentType != null && headers['Content-Type'] == null) {
      headers['Content-Type'] = contentType;
    }
    return $delegate.apply(null, arguments);
  };
}]);
Arne Hartherz
October 29, 2015Software engineer at makandra GmbH
Posted by Arne Hartherz to makandra dev (2015-10-29 13:45)