6

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.?

Cuthbert
  • 201
  • 1
  • 2
  • 9
  • I do this, but I encode the JSON in Base64 so it's not displayed plainly in the URL. (This doesn't add any security, it just makes the URL cleaner.) I don't see a problem in doing this, as long as the URL doesn't exceed 2000 characters. – Luc Apr 12 '16 at 20:08
  • 1
    @Luc: You consider a base64 encoding of a JSON object "clean"? – Robert Harvey Apr 12 '16 at 21:34
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackexchange.com/rooms/38521/discussion-on-question-by-cuthbert-what-is-the-correct-way-to-pass-json-objects). – yannis Apr 18 '16 at 09:19

2 Answers2

3

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.

Evan
  • 1,245
  • 1
  • 9
  • 18
1

You could use url params : http://localhost:5555/company/name/cuthbert/address/mainst

Or pass the json object as a string query param

NimChimpsky
  • 4,627
  • 4
  • 26
  • 39
  • I feel like I lose, at least in the context of hapi and joi, the ability to quickly validate and reject a request if it fails validation if I'm just passing JSON objects as strings. But url parameters in my example make sense. Am I still resigned to converting the JSON to a string for anything more complex? – Cuthbert Apr 13 '16 at 14:47
  • @Cuthbert you can still validate it server side when you convert the json to an object. An url params are validated by the framework easy peasy – NimChimpsky Apr 13 '16 at 14:49
  • I know I can always call joi.validate(), but I'd rather let the framework do it for me. – Cuthbert Apr 13 '16 at 14:55