HTTP, GET, and fuzzy semantics
A developer asked me a seemingly obvious question today:
I have an API
GETrequest that requires a
JSONbody. Is that okay?
It’s a good question too. It turns out the answer isn’t as simple as it should be. On principle the answer is, “No, it’s not cool”. A
GET is an idempotent request for a resource. You don’t request a resource with a resource (what would that mean?), you request it with a resource identifier. The
HTTP spec, however, is unclear on the subject and does not explicitly disallow it (it probably should).
This developer was using the request body as a convenient way to send a complex set of parameters, as
JSON is much more useful to work with than
URI encoded components. His approach was both sane and pragmatic. But, it was also incorrect.
Four reasons why you should avoid payloads GET requests
- It’s unexpected. You are not guaranteed that all
HTTPimplementations will treat it in the same way.
- The spec says so, sort of. Servers could/should ignore request bodies, as they have no semantic meaning to the request.
- It doesn’t play nicely with caching. Many caching layers use the URI as the cache hash. Unless the URI is changing between requests, the payload will not change the result of the request.
- It’s disingenuous. A
GETrequest uses a
URIto name the resource. The request body is irrelevant to that request.
Sometimes the simplest questions are not answered by the spec.
And how does the story end?
The developer recast the
GET as a
POST. The semantic of the request was to retrieve a customized resource based on specific parameters, essentially creating a new resource on the fly based on the given parameters. As the filters were non-trivial, they could not be cast as
HTTP headers or components of the
URI. This was a pragmatic fix too (one line in his tool chain).