Reputation: 133
I'm designing a RESTful api for a large collection of reporting data, I would like to pass a complex set of parameters like in the codeblock below. I'm debating between using POST and GET for this endpoint. Team member seem to favor GET but I am not sure the best way of passing this amount of data as GET parameters, best idea so far is to have one GET parameters called something like jsonparams
that would have all of the below json encoded
{
"filters":
[
{
"field": "metric-name",
"gt": (float/int),
"lt": (float/int)
},
{
"field": "metric-name-2",
"gt": (float/int),
"lt": (float/int)
}
],
"sort":
[
{
"field": "metic-name",
"order": "ASC"/"DESC"
},
{
"field": "metic-name-2",
"order": "ASC"/"DESC"
}
]
"limit": 100,
"offset": 0
}
Upvotes: 2
Views: 2304
Reputation: 41458
If you're adding the data to a resource or creating a resource use POST. GET is to get a already existing resource, not change the state of the resources.
Update: While
POST
request are fine to update a resource, if the action is idempotent (meaning will not result in creating new resource and every time you issue the request with the same parameters and data you can guarantee to the same resulting resource), then it's recommended to use aPUT
. If it's not idempotent, but you're not replacing the entire resource, usePATCH
if only updating part of the resource.
If the argument to go with a crazy serialized GET parameter based request for some kind of percived simplicity, you're not going to be adhearing to REST.
Now, if you're retrieving resources only (no creation), use GET. While I prefer human typable parameters, it's not required. If your situation is 100% retrieval you could encode the entire set into into a giant encoded param string, but I'd suggest at least splitting it out a bit for improved sanity by doing something like:
/resource?filters=urlencoded_filter_array&sort=urlencoded_sort_array&offset=0&count=100
Or you could go more explicit like:
/resource?filter1=urlencoded_filter_json&filter2=urlencoded_filter_json .... sort2=urlencoded_sort_json&offset=0&count=100
or finally (my favorite) a completely explicit broken out set of params
/resource?filter1_field=bah&filter1_gt=1.0&filter1_lt<2&filter2_field=boo&filter2_lt...
I like the final one because there's no encodeing/decoding of json and then url encoding the entire json string. This format is easy to decipher in access logs and trouble shoot. It's also very cacheable, even if the parameter order gets changed, some proxy caches can still work with this, whereas encoding some of the filters in a json object if they get moved around they look like entirely different values as far as proxies would be concerned. For me it's the most REST friendly (if that makes any sense), even though the first 2 examples are fine REST GET requests.
The added work to parse the parameter name isn't really that much fuss. A simple method could convert your json into the parameter string and another simple one could re-hydrate the json object from the explict filter1_xyz format.
Upvotes: 3
Reputation: 41928
POST is the method to use for any operation that isn't standardized by HTTP. Retrieval is standardized by the GET method, so using POST to retrieve information that corresponds to a potential resource is never RESTful. In theory, you should use GET, regardless of how convoluted your URI turns out to be.
However, since you're performing a query for which there isn't a single resource you could perform a GET to, it seems fine to use POST, as long as you're aware of the disadvantages and your documentation is clear about it. Frankly, I think using a POST is much clearer than encoding that payload as a JSON + base64 and sending it as a querystring merely for purism.
The real issue with using POST is when people use it in such a way that it avoids or prevents using a real URI. That doesn't seem to be the issue in your case, since you have a valid URI for the collection, but the semantics of your query are too complex to be expressed easily.
If you decide to go with GET, there's a catch. While the HTTP specs establish no limit for URIs, most implementations do, and you might hit that limit if you need to feed all those parameters as a querystring. In that case, it's RESTful to circumvent limitations of the underlying implementation, as long as that's decoupled from your application. A convention for doing what you want would be to use the POST method with the payload you described above, and the X-HTTP-Method-Override: GET
header.
Upvotes: 4