20

I have REST services which should receive really long queries via GET. Say for example I want to query a service with many geographical coordinates to find out something about all this coordinates.

1) My first thought was to use long URIs and increase the max URI length of the servlet container.

It would look like this:

GET http://some.test/myresource?query={really big JSON object}

But it seems that URIs longer than 2 KB are not reliable due to old proxy servers (is that right?).

2) My workaround is to create a temporary resource via POST first and use the URI of this resource as parameter in the actual GET request. That would look like this:

POST http://some.test/temp
Request Body: {really big JSON object}

201 Created Location: http://some.test/temp/12309871

GET http://some.test/myresource?query=http://some.test/temp/12309871

3) Use body of GET request. I've read the answers to the question whether it is a good idea to use the body of a GET request for the query, and the consensus is: no. Even Roy Fielding says that this is a bad idea.

4) Another approach could be to interpret POST as "create query result resource" and delete this resource after the request. But I consider that to be not RESTful and to be a bad idea.

Is there a better way to handle big queries with GET requests?

Community
  • 1
  • 1
deamon
  • 78,414
  • 98
  • 279
  • 415

6 Answers6

4

Use PUT.

Why? For the following reasons:

  • Just because the verb PUT 'may update' the resource, doesn't mean it will or must alter underlying state of the resource.
  • No new resource identifier (url) should be created by the API side of a PUT. Yes, technically a PUT with a client specified identifier is possible, but in this case you're hitting an existing resource.
  • PUT is like GET in the fact that it should be idempotent, meaning the results of the request will always be the same regardless of how often you call it and it has no side effects.

PUT means you're putting resource data to an existing resource. In terms of a article or post in the document / blog post worlds, it would be like uploading a new revision of some document to an existing resource URL. If you upload the same revision to the same URL, nothing should change in the resource you get back.

In your case, the geo data is some new resource data you're uploading and the result you get back should be the same every time you make the same request.

A more purist method to use the GET verb for the request might be:

  • Create an endpoint for a query resource type
  • POST the JSON set of query details to a query resource endpoint and get an identifier for the query resource (say it returns a query id of 123)
  • Submit to the get request a query identifier http://some.test/myresource?query_id=123
  • Delete the query resource 123

I see the pure method much more overhead than using PUT with query resource data in the body.

marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
Ray
  • 36,097
  • 17
  • 85
  • 129
3

I thought that the whole point in REST was to work on "documents" (or something alike). The URI part of a request is there to identify uniquely the resource to work on. The body part in contrast is there for the "contents" part of the document.

Hence, use the "body" part of the request.

Also note that the semantics of a "GET" request isn't supposed to be used for "PUTTING" or "POSTING" documents (comment in relation to your "query" example above which seems to "create" an object).

In any case, as you have pointed out, the URI part is limited (for good reason I am sure).


If you are concerned with caching, then the use of ETag/Last-Modified fields (in conjunction with "conditional GET" helps for this purpose.

jldupont
  • 82,560
  • 49
  • 190
  • 305
  • 2
    This is all within the rules, but there are some serious disadvantages in using the body of a GET request. Some are explained in this SO post: http://stackoverflow.com/questions/978061/ – Daniel Vassallo Jan 15 '10 at 11:27
  • 1
    If you are referring to caching for lowering transfer cost: you should anyhow use the Etag/Last-modified header fields which serve this purpose. "Conditional GET" helps for this purpose. – jldupont Jan 15 '10 at 11:39
2

Here is a slight variation on your second option. Create yourself a processor resource called QueryMaker. POST your parameters to it and let it redirect you to a temporary query resource that will return your results.

POST /QueryMaker
Body: Big Json representation of parameters

303: See Other
Location: http://example.org/TemporaryQueries/123213
Darrel Miller
  • 129,370
  • 30
  • 183
  • 235
1

If you are using a GET request to send large objects, you are not using REST correctly.

  • GET should be used for retrieving resources (via some sort of unique identifier)
  • POST should be used for creating resources (with the contents in the body)
  • PUT should be used for updating a resource (with the contents in the body)
  • DELETE should be used for deleting a resource

If you follow these guidelines you will never have to have overly long URIs.

Some best practice REST guidelines are here: http://www.xml.com/pub/a/2004/08/11/rest.html

DanSingerman
  • 34,397
  • 12
  • 76
  • 92
  • 2
    You might need to specify parameters for the way in which a resource is retrieved via GET (for example, 'include empty fields' or 'compress data' or 'open for editing')The question here is, how to pass those parameters, not what http verb to use. – axel_c Jan 15 '10 at 11:16
  • 3
    Specifying parameters is fine, but you have a badly designed REST service if you need ~2KB worth of parameters! – DanSingerman Jan 15 '10 at 11:21
  • I agree with you, but what is with list resources and params that filter this list? In my case these filter conditions can be really big and I don't know how to avoid them. I cannot work with short identifiers without filters. – deamon Jan 15 '10 at 11:27
  • 3
    I would seriously think about the design of your service. If you really really need >2 Kb of parameters, then I think what you are doing is fairly sensible - i.e. treating your params object as a different type of resource, which you create and then use against the resources in question here. – DanSingerman Jan 15 '10 at 11:42
  • Treat the params object as a resource is what I do with the temporary resource approach. I've added an example at the beginning to explain why I need such big query objects. – deamon Jan 15 '10 at 14:51
  • 4
    POST is absolutely not for updating a resource. It can be used as such, but it's not what it means. It means "hey you resource I'm posting to, take what I give you and do something with it, i'll wait for a response". Nothing else. – SerialSeb Jan 17 '10 at 01:59
  • 3
    Here's a simple example of a GET that has a very long parameter - you are passing in a SQL select that will determine what rows of data to return. A SQL select can easily be over 2K. But it is a simple request, return the selected data for the query. So it should be a GET, but can't be. – David Thielen Jun 20 '13 at 18:44
  • You can update the resource without changing the underlying state. Therefore `PUT` is a valid choice as you are always guaranteed to get the same result back from identical requests. – Ray Jun 21 '16 at 14:43
  • 1
    I'm down voting this answer - my reasoning is that it's reads like a copy and paste from the REST guidelines. In the real world, there's always use cases that don't seem to "fit" with best practices and you need guidance of what to do instead. An answer that just says "you are doing it wrong" isn't helpful. – Dave B 84 Oct 13 '16 at 10:03
0

The biggest limitation of URL lengths on the open Web is actually IE, which constraints them to 2083 characters.

Some proxies (e.g., all but the most recent versions of Squid) will limit them to about 4k, although this is moving towards 8k slowly.

Your #2 workaround is a good approach, depending on your use case.

Sending bodies on GETs may be allowed by some implementations, and disallowed by others, so it's a bad idea for interoperability as well as theoretical reasons. Most importantly, how will a cache know what to use as a key?

Mark Nottingham
  • 4,451
  • 1
  • 21
  • 20
-1

Can't you just send the big JSON data with the GET request body, instead of creating the temp resource?

Although it's not 100% kosher, i've found it works nicely with firefox and IE and IMO, the querystring is inelegant and usually exposes implementation details that don't belong in the URI. Just make sure to add a cache buster querystring parameter if you need up-to-date data because the server will ignore the data when determining whether it can return a cached response.

See here for a discussion of pros and cons of stuffing data in the GET request body.

Community
  • 1
  • 1
axel_c
  • 5,991
  • 2
  • 26
  • 40