One of my biggest bug bears with modern day APIs is when they fall over, you usually get back an HTML error page back from the proxy in between you and the API. In recent years, API driven apps have become more and more common; where you write your app built on top of an API rather than the API being a second thought.

Most commonly we see nginx placed infront of APIs for many reasons; be it load balancing, ssl termination, gzipping or just so that you don’t have to run your API process on port 80 or 443. There are other HTTP proxies out there but nginx seems to be the most commonly used for these purposes.

Who’s been developing against a JSON API only to get back an nginx plain white HTML error page stating 502 Bad Gateway? Anyone that’s developed against an API of some description has had this issue no doubt. Not only does it suck, and suck bad, but it means you have to either start dealing with error handling that knows how to deal with a HTML encoded response or you just don’t deal with it at all - it’s a pain to do.

There is another solution - go and tell the API provider to go and fix it. It’s really not that difficult to do, I’ll even show you how.


First of all, you need to create the JSON files that will be returned by nginx. Every API is different and you’ll want to create your files to follow your response format. So go and create JSON files for the following standard error codes:

400
401
403
404
405
406
407
412
415
500
501
502
503
504
505

Each of these needs a JSON file following the standard filename of <code>.json with the content that matches your API; in this case, when there’s an error, this API replies with an error key with the message.

{"error":"Bad Gateway"}

Next up, we need to make those files available to nginx and update the nginx configuration in the “site” configuration file. Below is a simplified example:

server {
    listen 80;

    server_name domain.tdl;

    location / {

        proxy_pass http://127.0.0.1:3000;
        proxy_redirect off;

        proxy_http_version 1.1;
    }


    error_page 400 /errors/401.json;
    error_page 401 /errors/402.json;
    error_page 403 /errors/403.json;
    error_page 404 /errors/404.json;
    error_page 405 /errors/405.json;
    error_page 406 /errors/406.json;
    error_page 407 /errors/407.json;
    error_page 412 /errors/412.json;
    error_page 415 /errors/415.json;
    error_page 500 /errors/500.json;
    error_page 501 /errors/501.json;
    error_page 502 /errors/502.json;
    error_page 504 /errors/504.json;
}

This let’s nginx know that when serving up an error, serve up a url internally of the error file. However, you need to give nginx some more information so it can deal with it, at the point it doesn’t know where to find the files. This is where you need to add a location directive within the server in the config file.

server { 

    ...

    location ^~ /errors/ {
        internal;

        root   /etc/nginx/static-files/;
        more_set_headers 'Content-Type: application/json charset=UTF-8';
    }
}

You’ll need to update the root path to wherever you placed your error files.

In this example the error files are located in /etc/nginx/static-files/errors/


The other benefit of giving back errors inside nginx is that you can now add CORS headers to these responses if your API usually gives them back - something that would break anyone needing them to integrate with your API; if those CORS headers aren’t there, the JavaScript in the browser won’t know if you’re giving back HTML or JSON anyway. There’s huge benefit to offload dealing with CORS headers to your nginx proxy even while the API is available, so I’ll write about that in another post soon.

It’s so simple to make your API accessible at all times; go and make your API fully accessible; even when your API process written in node, python or whatever isn’t.

EDIT: You can find that post about CORS headers using nginx here.