The correct way to pass JSON objects in an http request when a GET request is most appropriate

routingurlweb

One scenario is when you're creating a search endpoint. In the example below, I want to search a database of companies and the queries can become complicated; enough where I want to have the parameters passed as JSON objects instead of a flat list.

var hapi = require('hapi');
var joi = require('joi');

var server = new hapi.Server();
server.connection({port: 5555});

var simpleRoute = {
    method: 'GET',
    path: '/company/search',
    config: {
        validate: {
            query: {
                company: joi.object().keys({
                    name: joi.string(),
                    address: joi.string()
                })
            }
        }
    },
    handler: (request, reply) => {
        reply({
            input: request.query,
            results: 'SOME RESULTS'
        });
    }
};

server.route(simpleRoute);

server.start(() => {
    console.log('server started -- ' + server.info.uri);
});

And the url for this looks like http://localhost:5555/company/search?company=%7B%22name%22%3A%22Cuthbert%22%2C%22address%22%3A%22123%20Main%20St%22%7D.

The url is messy and doesn't look great and for a client-facing website, this can be difficult for a user to recreate if they wanted to redo a search.

There's also the character limit on urls. It's unlikely I'll hit it, but what happens a query becomes too complex for a GET request? I can change the route to POST/PUT, but the search also isn't modifying any data on my server.

So how do I pass complex objects over http while still making correct use of GET, PUT, POST, etc.?

Best Answer

Elastic Search has this issue, as well: their solution was to allow GET requests with bodies:

$ curl -XGET 'http://localhost:9200/twitter/tweet/_search' -d '{
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}
'

Though non-standard, it's not technically a violation of HTTP/1.1:

The presence of a message body in a request is signaled by a Content-Length or Transfer-Encoding header field. Request message framing is independent of method semantics, even if the method does not define any use for a message body.

However, RFC 7321 does acknowledge that bodies of GET requests have no defined semantics:

A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.

Because of this, clients don't technically need to support GET requests with bodies, and for this reason, Elastic Search also accepts search queries via POST.

Related Topic