This question already has answers here:
HTTP GET with request body
(23 answers)
Closed 7 years ago.
I don't want to see so long parameters string in the URI. So, can GET method use json data?
In my situation, I need to filter the result given kind of parameters. If there are a lot of parameter, the length may exceed the limit of URI. So, is there best practice for this problem?
In theory, there's nothing preventing you from sending a request body in a GET request. The HTTP protocol allows it, but have no defined semantics, so it's up to you to document what exactly is going to happen when a client sends a GET payload. For instance, you have to define if parameters in a JSON body are equivalent to querystring parameters or something else entirely.
However, since there are no clearly defined semantics, you have no guarantee that implementations between your application and the client will respect it. A server or proxy might reject the whole request, or ignore the body, or anything else. The REST way to deal with broken implementations is to circumvent it in a way that's decoupled from your application, so I'd say you have two options that can be considered best practices.
The simple option is to use POST instead of GET as recommended by other answers. Since POST is not standardized by HTTP, you'll have to document how exactly that's supposed to work.
Another option, which I prefer, is to implement your application assuming the GET payload is never tampered with. Then, in case something has a broken implementation, you allow clients to override the HTTP method with the X-HTTP-Method-Override header, which is a popular convention for clients to emulate HTTP methods with POST. So, if a client has a broken implementation, it can write the GET request as a POST, sending the X-HTTP-Method-Override: GET header, and you can have a middleware that's decoupled from your application implementation and rewrites the method accordingly. This is the best option if you're a purist.
To answer your question, yes you may pass JSON in the URI as part of a GET request (provided you URL-encode). However, considering your reason for doing this is due to the length of the URI, using JSON will be self-defeating (introducing more characters than required).
I suggest you send your parameters in body of a POST request, either in regular CGI style (param1=val1¶m2=val2) or JSON (parsed by your API upon receipt)
Related
This question already has answers here:
Which REST operation (GET, PUT, or POST) for validating information?
(6 answers)
Closed 5 years ago.
I want to implement a REST endpoint which general purpose is to validate complicated entity in JSON format.
So, the first question is which HTTP method should be used? We can't put JSON into body for GET method. POST and PUT are methods that should be used when some changes are done to the DB but validation doesn't make any changes.
And the second question is what resource name can be appropriate for such endpoint?
The main difference between POST and PUT is that PUT is idempotent while POST isn't.
So, the question is, if you run the same validation request twice, would you expect a different result? I guess no, so PUT probably is the best choice.
I you want to be effectively RESTful, one of the constraint is that an endpoint should target the resource you want to deal with, the HTTP method indicating what you want to do with it. So in your case, I would personally opt for:
PUT /api/v42/validation
As #RomanVottner proposed, you could also tackle this need by considering each request as a "new validation report generation", in which case POST would be more appropriate:
POST /api/v42/validations
Anyway, you're facing one of these edge cases where REST needs to be a bit tweaked, as this need is outside of the CRUD world.
My general rule is.. when you need a full JSON body, go with POST.
Have a post method like /validateJSON or something, GET would not work, PUT doesn't make sense, so go ahead with POST.
Refer to : Which REST operation (GET, PUT, or POST) for validating information?
Cheers.
I am trying to stick to the Restful design pattern for both JSON and HTML. My issue is the design for creating a new resource (amongst others, but this is the gist of the issue). IE:
JSON – POST to /resource creates a new resource.
JSON – GET to /resource returns a list of resources.
JSON – GET to /resource/{id} returns a resource.
HTML – POST to /resource creates a new resource.
HTML – GET to /resource returns a list of resources.
HTML – GET to /resource/{id} returns a resource.
All good so far – but I need a HTML form to actually create the data to send to the HTML POST. Obviously POST and GET already do things. I could use one of the below to return the HTML form:
HTML – GET to /resource?CREATE
HTML - GET to /resource?action=CREATE
HTML – GET to /resources/CREATE
But they seem like a kludge and not that intuitive.
Any thoughts or ideas?
EDIT - See my answer to my question below. At present this is (I consider) the best option.
I would indeed use something like /resources/create. If you want to allow for non-numeric identifiers, then this will not work. In that case you can identify a resource with a prefix, such as /resources/resource-{id} and then you can still use /resources/create.
I found this blog post really helpful to make URI scheme decisions: http://blog.2partsmagic.com/restful-uri-design/
In fact, you should leverage content negotiation (CONNEG) when you want to handle several formats within RESTful services.
I mean:
Set the Content-Type header to specify the type of sent data
Set the Accept header to specify the type of data you want to receive
The server resources should leverage these hints to make the appropriate data conversion.
In the case of JSON, the content type would be obviously application/json. For HTML form, you should leverage the content type application/x-www-form-urlencoded (or multipart/form-data if you want to upload files as well). See the specification for more details.
Otherwise, you shouldn't use action in URL since it's not really RESTful. The HTTP verb should determine the action to do on the resource. I mean, to create a resource, the POST method should be used. The GET method aims to retrieve the state of a resource.
For more details, you could have a look at this blog post:
Designing a Web API (i.e. RESTful service).
I have an answer. I'll use standard RESTful POST from a HTML page, but when I have no form parameters sent and my accept header is text/html, I'll send a HTML form to the requestor. Keeps RESTful URI design and allows a clean HTML form + process (2 step).
HTML - POST - /resources (with no form attributes) generates a HTML form
HTML - POST - /resources (with form attributes) adds a resource
JSON - POST - /resources (with form attributes) adds a resource
OK, it's not "strictly" RESTful as I'm POSTing but not creating a new resource so in theory I should use a GET for that, but it's the best of a mismatched design.
If anyone can provide a better solution, I'm still all ears :-)
I'd rather add and endpoint called /templates/ that returns a template/form/whatever you need for given action. It also seems that the server should be unaware of such form existence. It can accept or reject a request and it's client job to submit it in an appropriate format.
I guess that you mix processing the view with preparing RESTful endpoints. The backend site should be completely unaware of the fact that some sort of view/form is required. It's client job to prepare such form.
We are using the FOS Rest bundle, and, at first, we were unaware that the body listener was active.
In the meanwhile, we created a lot of resources that are receiving data via the body, in JSON format. For now we only support JSON format. Lot of them now in the controllers are retrieving parameters from the Symfony ParameterBag, because, body listener was injecting them there.
So, do you think is a good practice to leave to body listener the responsibility of that, and in the controllers retrieve parameters via the parameter bag? This way, no matter via GET, POST or body, all the parameters arrive to the controllers via parameter bag.
We are looking at this because some of our API clients were making requests without providing the content-type in the header, and because of that, body listener didn't inject the body in the parameter bag. So in the controllers we didn't have the parameters available.
Thanks in advance!
Generally speaking, one of the most important aspects of API design should be consistency across your implementation, so that your consumers understand how to interact with your system. To that end, I would follow this pattern:
Keep the body listener enabled if it assists with your development; this listener is a shortcut to help you write simpler controllers, so if it is working for you, there's no reason to abandon it
For API endpoints that expect a JSON request body, report to the consumer that they are making an illegal request if the proper Content-type: application/json header is missing (which can be done via setting a _format requirement on the route; see advanced routing example)
If you must support these legacy users that are not passing the header, you could create a listener on the kernel.request event with a very high priority which simply checks for the detected mime type and, and if it is missing, does something like this:
if ($request->getRequestFormat() != 'json') {
json_decode($request->getContent());
if (json_last_error() == JSON_ERROR_NONE) {
$request->setRequestFormat('json');
}
}
(The use of json_last_error() is not perfect here; see this question for a more detailed discussion.)
Finally, if you aren't already, make sure that you are restricting your API controllers to the proper request method, again to make sure that they are being consumed correctly and to make your development and use more consistent. If you are using annotations, for example, this is as simple as using the FOSRestBundle-provided #Get, #Post, etc. in place of the usual #Route. If you are using YML or XML configuration, it's the methods property.
Although it is certainly possible for a single controller to accept data via a GET (with request parameters), a POST (via URL-encoded form data), or a POST or PUT with JSON data and a body listener-conversion, this makes for a very convoluted API, as you have to start maintaining these different cases, and I would argue that things become very difficult for your users as well.
As a consumer of these APIs, I would expect my requests to fail if I were passing JSON in a request body but not including the proper header, and I would expect my requests to fail if I were passing x-www-form-urlencode data to a JSON-based API. Overall, both for the maintainer of an API and for the consumers, it is a good idea to be strict on what you accept and to follow the same pattern throughout.
A REST API can have arguments in several places:
In the request body - As part of a json body, or other MIME type
In the query string - e.g. /api/resource?p1=v1&p2=v2
As part of the URL-path - e.g. /api/resource/v1/v2
What are the best practices and considerations of choosing between 1 and 2 above?
2 vs 3 is covered here.
What are the best practices and considerations of choosing between 1
and 2 above?
Usually the content body is used for the data that is to be uploaded/downloaded to/from the server and the query parameters are used to specify the exact data requested. For example when you upload a file you specify the name, mime type, etc. in the body but when you fetch list of files you can use the query parameters to filter the list by some property of the files. In general, the query parameters are property of the query not the data.
Of course this is not a strict rule - you can implement it in whatever way you find more appropriate/working for you.
You might also want to check the wikipedia article about query string, especially the first two paragraphs.
I'll assume you are talking about POST/PUT requests. Semantically the request body should contain the data you are posting or patching.
The query string, as part of the URL (a URI), it's there to identify which resource you are posting or patching.
You asked for a best practices, following semantics are mine. Of course using your rules of thumb should work, specially if the web framework you use abstract this into parameters.
You most know:
Some web servers have limits on the length of the URI.
You can send parameters inside the request body with CURL.
Where you send the data shouldn't have effect on debugging.
The following are my rules of thumb...
When to use the body:
When the arguments don't have a flat key:value structure
If the values are not human readable, such as serialized binary data
When you have a very large number of arguments
When to use the query string:
When the arguments are such that you want to see them while debugging
When you want to be able to call them manually while developing the code e.g. with curl
When arguments are common across many web services
When you're already sending a different content-type such as application/octet-stream
Notice you can mix and match - put the the common ones, the ones that should be debugable in the query string, and throw all the rest in the json.
The reasoning I've always used is that because POST, PUT, and PATCH presumably have payloads containing information that customers might consider proprietary, the best practice is to put all payloads for those methods in the request body, and not in the URL parms, because it's very likely that somewhere, somehow, URL text is being logged by your web server and you don't want customer data getting splattered as plain text into your log filesystem.
That potential exposure via the URL isn't an issue for GET or DELETE or any of the other REST operations.
We're having a bit of a discussion on the subject of posting data to a REST endpoint. Since the objects are quite complex, the easiest solution is to simply serialize them as JSON and send this in the request body.
Now the question is this: Is this kosher? Or should the JSON be set as a form parameter like data=[JSON]? Or is sending of JSON in the request body just frowned upon for forcing the clients using the application, to send their data via JavaScript instead of letting the browser package it up as application/x-www-form-urlencoded?
I know all three options work. But which are OK? Or at least recommended?
I'd say that both methods will work well
it's important that you stay consistent across your APIs. The option I would personally choose is simply sending the content as application/json.
POST doesn't force you to use application/x-www-form-urlencoded - it's simply something that's used a lot because it's what webbrowsers use.
There is nothing wrong about sending it directly as serialized JSON, for example google does this by default in it's volley library (which obviously is their recommended REST library for android).
If fact, there are plenty of questions on SO about how not to use JSON, but rather perform "normal" POST requests with volley. Which is a bit counter intuitive for beginners, having to overwrite it's base class' getParams() method.
But google having it's own REST library doing this by default, would be my indicator that it is OK.
You can use JSON as part of the request data as the OP had stated all three options work.
The OP needs to support JSON input as it had to support contain complex structural content. However, think of it this way... are you making a request to do something or are you just sending what is basically document data and you just happen to use the POST operation as the equivalent of create new entry.
That being the case, what you have is basically a resource endpoint with CRUDL semantics. Following up on that you're actually not limited to application/json but any type that the resource endpoint is supposed to handle.
For non-resource endpoints
I find that (specifically for JAX-RS) the application/x-www-urlencoded one is better.
Consistency with OAuth 2.0 and OpenID Connect, they use application/x-www-urlencoded.
Easier to annotate the individual fields using Swagger Annotations
Swagger provides more defaults.
Postman generates a nice form for you to fill out and makes things easier to test.
Examples of non-resource endpoints:
Authentication
Authorization
Simple Search (though I would use GET on this one)
Non-simple search where there are many criteria
Sending a message/document (though I would also consider multipart/form-data so I can pass meta data along with the content, but JAX-RS does not have a standard for this one Jersey and RestEasy have their own implementations)