8

I'm actually rewritting some APIs (in ASP.Net Core 3.1) we have at work and we try to make them RESTFull. I run into some methods where It should be called with HTTP GET because it's for retrieving some data but the parameters are wrapped in a pretty large DTO.

So I was asking myself how to deal with it :

  • Let it put the DTO in the URL but then what are the limitation in size?
  • Put a body in the HTTP GET request. I made some search but the results I found were old. Apparently it's allowed but discouraged back in the time
  • Use HTTP Post, but then it's not REST because POST should be used to create data

I think the better solutions will be to use HTTP Get with body (according to this article https://thecodebuzz.com/http-get-delete-request-body-guidelines/ it's possible)

Have someone had the same issue? What are the guideline now a days?

Thanks for your thoughts

S.Martignier
  • 383
  • 2
  • 4
  • 17
  • If you have a seach-like endpoint that accepts a lot of parameters, just make it POST. If you don't, and you aren't able to call your service "fully REST", what happens? Nobody will care. – CodeCaster Jul 31 '20 at 11:24
  • 1
    Does this answer your question? [HTTP GET with request body](https://stackoverflow.com/questions/978061/http-get-with-request-body) – Zinov Jul 31 '20 at 11:32
  • @Zinov I've already read this post, but since it was made 11 years ago I was not sure It was still pertinent @ CodeCaster I know It's not such a big deal, but being a young programmer I want to learn as much best practice when I don't have bad habit of coding – S.Martignier Jul 31 '20 at 11:35
  • @S.Martignier there are a bunch of questions/answers around this similar topic, this will be creating a new thread of answers that are no needed. But answering part of your question, when you pass something in the body of your request you should use a Content-Type instead, semantically for the GET is wrong. Also you can check the specification here https://tools.ietf.org/html/rfc7231#section-3.1.1.5 . Also if you create a documentation for your API using swagger, the latest standard of openapi will be complaining about the body on a GET – Zinov Jul 31 '20 at 12:01

4 Answers4

17

I think the better solutions will be to use HTTP Get with body

RFC 7231 thinks otherwise:

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.

You can't count on general purpose components doing useful things with the body. For instance, caches will be using the target-uri as the primary cache key, and won't be considering the body at all. So strange behavior is likely there.

In effect, GET with a body is only going to work if you control the client, the web server, and the components in between. And if that is the case, you might as well define your own HTTP method with the semantics that you want it to have.

For example, you might look into HTTP SEARCH, and see if those semantics are a better fit for what you are trying to do.

That said, if you are trying to color inside the lines, it is okay to use POST.

POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”


it's not REST because POST should be used to create data

REST doesn't define any sort of "create" constraint. REST says "use the appropriate method defined in the uniform interface"; HTTP says "use POST when no more specific method fits".

But if you are in an environment that won't accept that... one way to achieve what you want without "breaking the rules" is to think about creating a new resource that is the results of your query. So we POST some information, and that information gets associated with a new URI controlled by the server, and then subsequent attempts to GET the resource give you the results you want.

POST /foo

201 Created
Location: /c30e910e-7baa-4c31-9481-4c84c12884a1  
...Other Headers...

GET /c30e910e-7baa-4c31-9481-4c84c12884a1

200 OK
Content-Location: /c30e910e-7baa-4c31-9481-4c84c12884a1
...Other Headers...

The Answer

Following the standards, you can combine those two ideas to save a round trip

POST /foo

201 Created
Location: /c30e910e-7baa-4c31-9481-4c84c12884a1  
Content-Location: /c30e910e-7baa-4c31-9481-4c84c12884a1
...Other Headers...

The Answer

From there, it's a small step to

POST /foo

200 OK
...Other Headers...

The Answer
Community
  • 1
  • 1
VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
3

You have a good collection of questions, I'll answer based on my experience.

URL Limitation in size Generally, there is no limitation, but it's up to the browser and server, for example, Internet Explorer and Edge support 2083 Characters.

The HTTP specification provides HTTP Status Code 414, which will be returned when the server cannot handle the URL size.

.

Put a body in HTTP GET

Although technically it's possible, it's not the best practice.

The purpose of API is to share with other developer/application, so if you write a non-standard API it must be difficult for other developers who are going to consume it.

.

Use HTTP POST for Create

The restfulness is based on your architecture, not from the HTTP call you are going to use. Give meaningful response to the create call (HTTP Status Code 201)

Christlin Panneer
  • 1,599
  • 2
  • 19
  • 31
1

It is still discouraged today. OAS3.0 which is used to design API definitions wont even allow it.

Have you read some of the REST design principles: Hackernoon Or Style guides Adidas API guide ?

They will help you on your path to being RESTful. If you have a "collection resource" that you need to filter, use query parameters if its really complex then is it a search in which case Post a body via a "controller resource".

If you want to provide some more details on the use case, peeps here will be happy to help.

API Alex
  • 106
  • 1
  • 1
  • 6
  • 1
    Thanks for the answer. About OAS3 can you point me to the part where it's say that they don't allow it? Because when I was making some research I found this PR https://github.com/OAI/OpenAPI-Specification/pull/2117 that allow body for GET For the Hackernoon article in the description of the POST they say it's for creating data (which I Know) and later in the article they said that if a GET request as a too long URL use POST so weird Can you tell me more about "Post a body via controller resource"? I don't understand what it's mean – S.Martignier Jul 31 '20 at 07:59
  • Hey, Your most welcome. I only found out about it as I imported an old API Blueprint into OAS3 and was warned it doesnt support Bodies with GETs, Its referenced on this page from SwaggerHub https://swagger.io/docs/specification/describing-request-body/, Regarding posting to a controller that would be used for searching for things (these are the only resources that should have verbs in their names) Have a read through the naming conventions that gets into it https://restfulapi.net/resource-naming/. Your link is interesting though that they merged it for OAS 3.0.1! Remains discouraged – API Alex Jul 31 '20 at 08:30
0

Voice already mentioned most of the stuff relevant to REST, such as

  • use POST if other methods are not sufficient enough
  • use customized methods when you in full control of the environment (i.e. each client, server and intermediary is run by you)

The latter one, however, should always be treated with care as once you let external peers into this environment they need customization as well.

Please, regard this post as some kind of addendum to Voice's post as his post, IMO, is missing an important design philosophy often used in REST architectures: servers should teach clients what they need to take next actions!

In HTML we are all to familiar with Web forms and how they can be used to teach clients on what properties a resource supports. But these forms also teach a client on where to send the request to, which HTTP operation to use and, mostly implicitly given, also the media type to use to marshal the data into before sending the actual request. Though most of those so called REST APIs (which truely behave like classic RPC ones) do not even consider form-like representations at all although some drafts exists such as hal-forms, halo+forms or ion.

The advantage on introducing an intermediary layer that describes what properties a resource supports is that this representation is in essence cacheable as it probably wont change often. In case of a modification an unsafe operation is performed on that form-resource that leads to invalidation of any stored representation for the respective URI. This way clients will also learn on the fly about the new or updated properties a certain resource supports and expects and thus wont need any external documentation.

The product resource of such a form-resource could be stored further and given a meaningful name intended for later usage as well, i.e. such as a desired view. This resource in essence would encapsulate all of the requests parameters such as query term or fields. A client could now simply issue a GET request against this pre-stored query in order to retrieve its result. On doing this, any response yielded by that query is yet again cacheable and thus in-line with any constraints put up by the REST architecture.

This also goes hand in hand by Fielding's statement that a REST architecture usually has plenty more resources than domain objects. Besides the actual resource holding more or less the data of the business object, you also have a form-resource that teaches clients on how a request has to look like and potentially a resource that stores all of the request parameters for laster usage.

Roman Vottner
  • 12,213
  • 5
  • 46
  • 63