FOSRestBundle - is a good practice to inject body params in the parameter bag? - json

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.

Related

Restful design pattern for HTML

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.

For Restful API, can GET method use json data? [duplicate]

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&param2=val2) or JSON (parsed by your API upon receipt)

JSON vs Form POST

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)

Using MVC3's AntiForgeryToken in HTTP GET to avoid Javascript CSRF vulnerability

In regards to this Haacked blog, I'm hesitant to implement the proposed anti-JSON GET hijacking solutions since
The recommended solutions to mitigating JSON hijacking involve non-REST-full JSON POSTs to GET data
The alternate solution (object wrapping) causes problems with 3rd party controls I don't have source-code access to.
I can't find a community-vetted implementation that implements the Alternative Solution (listed below) on how to compose the security token, or securely deliver it within the webpage. I also won't claim to be enough of an expert to roll my own implementation.
Referrer headers can't be relied upon
Background
This blog describes a CSRF issue regarding JSON Hijacking and recommends using JSON POSTs to GET data. Since using a HTTP POST to GET data isn't very REST-full, I'd looking for a more RESTfull solution that enables REST actions per session, or per page.
Another mitigation technique is to wrap JSON data in an object as described here. I'm afraid this may just delay the issue, until another technique is found.
Alternative Implementation
To me, it seems natural to extend the use ASP.NET MVC's AntiForgeryToken with jQuery HTTP GETs for my JSON.
For example if I GET some sensitive data, according to the Haacked link above, the following code is vulnerable:
$.getJSON('[url]', { [parameters] }, function(json) {
// callback function code
});
I agree that it isn't RESTfull to GET data using the recommended POST workaround. My thought is to send a validation token in the URL. That way the CSRF-style attacker won't know the complete URL. Cached, or not cached, they won't be able to get the data.
Below are two examples of how a JSON GET query could be done. I'm not sure what implementation is most effective, but may guess that the first one is safer from errant proxies caching this data, thus making it vulnerable to an attacker.
http://localhost:54607/Home/AdminBalances/ENCODEDTOKEN-TOKEN-HERE
or
http://localhost:54607/Home/AdminBalances?ENCODEDTOKEN-TOKEN-HERE
... which might as well be MVC3's AntiForgeryToken, or a variant (see swt) thereof. This token would be set as an inline value on whatever URL format is chosen above.
Sample questions that prevent me from rolling my own solution
What URL format (above) would you use to validate the JSON GET (slash, questionmark, etc) Will a proxy respond to http://localhost:54607/Home/AdminBalances with http://localhost:54607/Home/AdminBalances?ENCODEDTOKEN-TOKEN-HERE data?
How would you deliver that encoded token to the webpage? Inline, or as a page variable?
How would you compose the token? Built in AntiforgeryToken, or by some other means?
The AntiForgeryToken uses a cookie. Would a backing cookie be used/needed in this case? HTTP Only? What about SSL in conjunction with HTTP Only?
How would you set your cache headers? Anything special for the Google Web Accelerator (for example)
What are the implications of just making the JSON request SSL?
Should the returned JSON array still be wrapped in an object just for safety's sake?
How will this solution interop with Microsoft's proposed templating and databinding features
The questions above are the reasons I'm not forging ahead and doing this myself. Not to mention there likely more questions I haven't thought of, and yet are a risk.
The Asp.net MVC AntiForgeryToken won't work through HTTP GET, because it relies on cookies which rely on HTTP POST (it uses the "Double Submit Cookies" technique described in the OWASP XSRF Prevention Cheat Sheet). You can also additionally protect the cookies sent to the client by setting the as httponly, so they cannot be spoofed via a script.
In this document you can find various techniques that can be used to prevent XSRF. It seems the you described would fall into the Approach 1. But we have a problem on how to retrieve the session on the server when using Ajax HTTP GET request since the cookies are not sent with the request. So you would also have to add a session identifier to you action's URL (aka. cookieless sessions, which are easier to hijack). So in order to perform an attack the attacker would only need to know the correct URL to perform the GET request.
Perhaps a good solution would be to store the session data using some key from the users SSL certificate (for example the certs thumb-print). This way only the owner of the SSL certificate could access his session. This way you don't need to use cookies and you don't need to send session identifiers via query string parameters.
Anyway, you will need to roll out your own XSRF protection if you don't want to use HTTP POST in Asp.net MVC.
I came to this problem and the solution was not so trivial however there is a fantastic blog to get you started this can be used with get and post ajax.
http://johan.driessen.se/posts/Updated-Anti-XSRF-Validation-for-ASP.NET-MVC-4-RC
If you place the following in the global name space all your post/gets can take advantage having an anti forgery token and you don't have to modify your ajax calls. Create an input element in a common page.
<form id="__AjaxAntiForgeryForm" action="#" method="post">#Html.AntiForgeryToken()</form>
The following javascript will read the anti forgery tokken and add it to the request header.
// Wire up the global jQuery ajaxSend event handler.
$(document).ajaxSend(namespace.ajax.globalSendHandler);
// <summary>
// Global handler for all ajax send events.
// </summary>
namespace.ajax.globalSendHandler = function (event, xhr, ajaxOptions) {
// Add the anti forgery token
xhr.setRequestHeader('__RequestVerificationToken', $("#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]").val());
};
I think it is legitimate to use AntiforgeryToken (AFT) within an ajax http GET request provided that it is embedded in a form that already provides the AFT and associated cookie. The ajax handler can then do the validate on the server just how it would in a normal form post.

How to send HTML form RESTfully?

I have a URI for a collection of resources called 'facts', and URIs for each 'fact' resource in that collection.
The form for creating a new 'fact' should be requested with a GET, I believe, but I'm having trouble deciding what URI it should be made to.
A GET to the collection URI should return a list of the 'fact' resource URIs. Each 'fact' URI should return its contents as a response to GET. The actual 'fact' creation would be a POST (or PUT, depending on the situation), of course.
I see a few options, but none seem satisfactory:
Add a 'fact form' URI which the 'facts' URI will reference. A GET to this URI gives the HTML form. Seems wrong to have another resource just for a description of a resource.
A POST made to the 'facts' URI without including any form data in the headers would return the form. Then after the user fills the form in, it would POST with the form data, and create the new 'fact' resource. This seems like an even worse approach.
Don't send the form over the wire, but include it as part of the API. This seems RESTful since a REST API should describe the media types, and a form can be made from a description of the 'fact' type. This is weird to implement. Maybe the REST service is separate from the regular web site, so that the actual HTML form request is at some URI apart from the REST API.
Include the HTML form as part of the 'facts' URI response.
To clarify, I'm trying to follow true REST architecture as specified by Roy Fielding, not half-baked RPC posing as REST.
edit: I'm starting to think #3 is on to something.
edit2: I think a solution is to have regular non-REST HTML navigation in a CRUD manner, and then the frontend makes AJAX REST calls as appropriate (or the backend makes internal calls to its REST API).
The reason I need to do the REST part of this service correctly is that I want to allow other non-HTML clients to interact with it later on.
In my mind, the only cleanly RESTful answers are 1 and 3.
As I see it, the description of the resource is a resource of its own. The question is whether you want to make this resource accessible through your application's API or if you want to make it part of the API itself.
For 1, it seems RESTful make the URIs something like this:
GET /facts -> all facts
GET /facts/1 -> returns fact 1 (obviously the id might be a word or something else)
GET /facts/create -> returns a form appropriate for creating a fact
POST /facts -> adds a fact
I think you're overcomplicating things a bit. A web browser is just not a perfect REST client, so you can't have a perfectly RESTful solution. In a perfect world, you would not need a form at all, because the web browser would know your media types and build the form itself.
Meanwhile, I suggest you just use what most REST frameworks would call an additional "view" on the resource to return a form:
E.g. /your/collectionresource?view=form, or /your/collectionresource;form