I want to use a REST API with hypermedia constraint to drive my UI.
That is, depending on "possible next states" for the resources I fetch, I want to adapt my UI for this.
I'm quite new to UI dev on the web so I wonder if there is any special considerations I need to care about here?
Lets say I have a resource that looks like this:
{
href: "..",
orderDate: date..,
details: {
href : "..",
items: [..],
}
links: [
placeOrder : {
href : "...",
method : "post"
},
cancelOrder : {
href : "...",
method : "delete"
}]
}
Would the above links approach be valid within the context of HATEOAS ?
In a perfect world I guess one should just know about HTTP verbs for actions on the resource but if I want to let the UI know about what can be done to the resource, how do I do this in an idiomatic way?
What I mean is, the same kind of resource can have different "next possible state" depending on current status. And the UI needs to know about this.
Should the UI examine what links are available on the resource or how do I do this?
Yes, exactly. The UI should be coded entirely to the link relations presented to it. If a relation isn't available to follow, it shouldn't be returned in the link collection in the response. That drives not only current state, but also means that the UI isn't burdened with trying to calculate access control rules.
If by idiomatic you mean systematic then the description of the processing rules for the JSON you return need defining, then you communicate your cool new media-type via the Content-Type header.
https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types. Any effort spent describing what methods to use on what URIs of interest should be entirely defined within the scope of the processing rules for a media type (and, in most cases, already defined by existing media types). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]
He's saying to put all your effort into figuring out how to design a data format and its rules such that the system is fully expressive for all its needs, like HTML.
(Or skip this and just use HTML for your API).
Related
I got called "unprofessional" today because I didn't nest my JSON response in a parent object.
GET /users/{id} responds with this:
{
"username":"atr217",
"age":35,
...
}
They expected this:
{
"user":{
"username":"atr217",
"age":35,
...
}
}
Or maybe this:
{
"status":200,
"message":"OK"
"data":{
"username":"atr217",
"age":35,
...
}
}
I've seen it done both ways. Is the best practice to wrap the data in a parent? If so, why? And what else goes in the parent?
I'm using SwaggerHub and OpenAPI 3, if that matters.
I found the correct Google search term: "envelope"
RESTful API Design Tips from Experience
“I do not like enveloping data. It just introduces another key to navigate a potentially dense tree of data. Meta information should go in headers.”
“One argument for nesting data is to provide two distinct root keys to indicate the success of the response, data and error . However, I delegate this distinction to the HTTP status codes in cases of errors.”
“Originally, I held the stance that enveloping data is not necessary, and that HTTP provided an adequate “envelope” in itself for delivering a response. However… I now recommend enveloping.”
When in my REST API should I use an envelope? If I use it in one place, should I always use it?
“HTTP is your envelope… Having said that, there is nothing wrong with having a descriptive body on a response”
Best Practices for Designing a Pragmatic RESTful API
“Don’t use an envelope by default, but make it possible when needed”
“We can future proof the API by staying envelope free by default and enveloping only in exceptional cases.”
“There are 2 situations where an envelope is really needed - if the API needs to support cross domain requests over JSONP or if the client is incapable of working with HTTP headers.”
“Envelope loving APIs typically include pagination data in the envelope itself. And I don’t blame them - until recently, there weren’t many better options. The right way to include pagination details today is using the Link header introduced by RFC 5988.”
I am looking at defining a REST API using HATEOAS. In particular, I find very interesting the concept of indicating for a given resource the actions that are available right now.
Some of the HATEOAS specifications include too much overhead for my needs, so I was looking at the HAL specification, as I find it very concise and practical:
{
_links: {
self: { href: "/orders/523" },
warehouse: { href: "/warehouse/56" },
invoice: { href: "/invoices/873" }
},
currency: "USD",
status: "shipped",
total: 10.20
}
However, links in HAL only contain a list of related resources, but not the available actions on them. As per the example above, am I allowed to cancel the order now, or not anymore? Some HAL examples solve this by using a specific URL for cancellations, and add a corresponding link in the response only if cancellation is possible:
"cancel": { "href": "/orders/523/cancel" }
But that is not very RESTful. Cancellations are not a resource. Cancellations are a DELETE of a resource, i.e.:
DELETE /orders/523
Is there a nice way to represent this with HAL, or should I use a different HATEOAS specification?
I am considering returning a "cancel" link with the same URL as self, but in this case the client would have to know that to cancel they have to use the DELETE verb, which is not really being described in the HATEOAS response.
self: { "href": "/orders/523" },
cancel: { "href": "/orders/523" }
Would this be the recommended approach as per HATEOAS / HAL? I understand HAL does not have any "method" parameter, and adding it myself would be against the HAL specification.
Some HAL examples solve this by using a specific URL for cancellations, and add a corresponding link in the response only if cancellation is possible
Yes. Just like web sites: if you want to alert the client to the possibility of reaching some other application state, you provide the client with a link, including the identifier for the resource involved.
But that is not very RESTful.
It may not be "RESTful", but it is certainly conforms to the REST architectural style.
Cancellations are a DELETE of a resource, i.e.: DELETE /orders/523
You are confusing the actions on the domain model with the actions on the integration model. What a REST API does is guide the client through a protocol to achieve some end; it is not a mapping of domain semantics onto HTTP.
Jim Webber phrased it this way:
The web is not your domain; it's a document management system. All of the HTTP verbs apply to the document management domain. URIs do NOT map onto domain objects -- that violates encapsulation. Work (ex: issuing commands to the domain model) is a side effect of managing resources.
One of the REST constraints is the uniform interface; in the case of HTTP, it means that all resources understand methods in a uniform way; DELETE means the semantics described in RFC 7231, section 4.3.5.
In other words, if I send the request
OPTIONS /x/y/z/foobar ...
and the response includes DELETE in the Allow header, then I know what it means. The side effects in your domain? I don't know anything about the side effects.
In the definition of DELETE, note the following
Relatively few resources allow the DELETE method -- its primary use is for remote authoring environments, where the user has some direction regarding its effect.
Anyway, you aren't really asking about DELETE, but about HAL
Is there a nice way to represent this with HAL, or should I use a different HATEOAS specification?
From what I can tell, the official way to do it is to document it with the link relation. In other words, instead of using "cancel" as the link relation, you use something like
https://www.rfc-editor.org/rfc/rfc5023#section-5.4.2
And then your consumers, if they want to discover what a link is for, can follow the relation to learn what is going on.
HAL Discuss: Why No Methods? has a lot of good information.
I like Mike Kelly's summary:
The idea is the available methods can be conveyed via the link
relation documentation and don't need to be in the json messages.
According to this article from LosTechies, in a CQRS perspective, Its accepted to use URLs such as: /orders/<id>/<command> and call these with PUT requests. So its OK to use a "cancel": { "href": "/orders/523/cancel" }.
However, if you absolutely want to use DELETE and you only use command links to modify your ressources (i.e. /orders/<id>/<command>) like proposed the article, why can't you just add a link such as "cancel": { "href": "/orders/523" } and deduct the HTTP verb?
I mean according to REST there is only 5 main verbs (GET, POST, PUT, PATCH and DELETE). We can't use POST on a URL such as /<ressource>/<id>, GET is already define as the "self" relation, we mentioned above that modifications (PUT) will be handled by command links (i.e. /<ressource>/<id>/<command>) and because we use command links there is no need to use PATCH. After that, the only option left is: DELETE.
It's not perfect, but it works and it doesn't break any convention.
I have this question that has been going around through my head for a while. Lets suppose we have structured our project with backend and frontend on separate layers. So, from the frontend, we want to get a costumer, which comes on hal+json format:
GET /customers/1 HTTP/1.1
Accept: application/hal+json
{
"name": "Alice",
"links": [ {
"rel": "self",
"href": "http://localhost:8080/customer/1"
} {
"rel": "transactions",
"href": "http://localhost:8080/customer/1/transactions"
}]
}
Then, from the frontend i want to get all customer transactions. My question is: how should i get the url? should it be from the response? or should i build it internally?
if we go with first option, i think that maybe that wouldn't be elegant to iterate all links until we get that one we want. Also, there could happen the situation where we don't have the link of the request we want to do.
if we go with second option, i don't understand how to build that url if we don't actually have the ids. How could i create new customer transactions if hateoas replaces ids with links and i haven't got the object reference in the body anymore?
I thought that maybe service should support both application/hal+json(oriented to users) and application/json(oriented to clients) but i don't see that this is how is making it done generally.
What do you think?
Definitely the first option. Namely, since HATEOAS is a final stage of Richardson Maturity Model, clients are expected to follow the provided links, not to build the URLs by themselves:
The point of hypermedia controls is that they tell us what we can do
next, and the URI of the resource we need to manipulate to do it.
Rather than us having to know where to post our appointment request,
the hypermedia controls in the response tell us how to do it.
What benefits does this bring? I can think of at least two:
Simple upgrade of the REST API - server-side developers can change the URIs of the resources, without breaking the client-side code because clients just follow the provided links; additionally, server-side developers can easily add new links
Robustness - by following the links, client-side code would never try to access the broken links, misspelled links etc.
Q: Also, there could happen the situation where we don't have the link of the request we want to do?
It is up to API designer to ensure that all required links are provided. Front-end developer shouldn't worry about that.
See also:
Rest lesson learned - avoid hackable URLs
HATEOAS (Hypermedia as the Engine of Application State) is a constraint of the REST application architecture. You can have a look on Spring HATEOAS documentation for instance :
https://spring.io/understanding/HATEOAS
Another link about it using Spring and AngularJS is available here:
AngularJS and Spring HATEOAS tutorial
This one seems to be good enough and handles your use case.
Regards, André
I am developing a small web api in PHP and try to make it as restful as possible.
Currently i'm working on some kind of a "homepage" which should be a json represented overview of what the client can do without having to read a documentation. I discovered the json-home format (see draft-nottingham-json-home-02) what seems to be quite useful in my case. But since it's not spread that much it's hard to find examples. What I don't understand is what the "href-vars" - attribute is (see 4.1. Resolving Templated Links).
For example I have a route /api/documents/{id} what gives me the json representation for one single document. Obviously this is a template-link resource in json-home format, but what would be my href-vars : { id: } ?
HREF-VARS is used to specify a parameter for URL Templating.
The URI is firstly a unique identifier for the parameter. The URL could contain documentation regarding the type of the parameter.
I have a collection resource called Columns. A GET with Accept: application/json can't directly return a collection, so my representation needs to nest it in a property:-
{ "propertyName": [
{ "Id": "Column1", "Description": "Description 1" },
{ "Id": "Column2", "Description": "Description 2" }
]
}
Questions:
what is the best name to use for the identifier propertyName above? should it be:
d (i.e. is d an established convention or is it specific to some particular frameworks (MS WCF and MS ASP.NET AJAX ?)
results (i.e. is results an established convention or is it specific to some particular specifications (MS OData)?)
Columns (i.e. the top level property should have a clear name and it helps to disambiguate my usage of generic application/json as the Media Type)
NB I feel pretty comfortable that there should be something wrapping it, and as pointed out by #tuespetre, XML or any other representation would force you to wrap it to some degree anyway
when PUTting the content back, should the same wrapping in said property be retained [given that it's not actually necessary for security reasons and perhaps conventional JSON usage idioms might be to drop such nesting for PUT and POST given that they're not necessary to guard against scripting attacks] ?
my gut tells me it should be symmetric as for every other representation but there may be prior art for dropping the d/*results** [assuming that's the answer to part 1]*
... Or should a PUT-back (or POST) drop the need for a wrapping property and just go with:-
[
{ "Id": "Column1", "Description": "Description 1" },
{ "Id": "Column2", "Description": "Description 2" }
]
Where would any root-level metadata go if one wished to add that?
How/would a person crafting a POST Just Know that it needs to be symmetric?
EDIT: I'm specifically interested in an answer that with a reasoned rationale that specifically takes into account the impacts on client usage with JSON. For example, HAL takes care to define a binding that makes sense for both target representations.
EDIT 2: Not accepted yet, why? The answers so far don't have citations or anything that makes them stand out over me doing a search and picking something out of the top 20 hits that seem reasonable. Am I just too picky? I guess I am (or more likely I just can't ask questions properly :D). Its a bit mad that a week and 3 days even with an )admittedly measly) bonus on still only gets 123 views (from which 3 answers ain't bad)
Updated Answer
Addressing your questions (as opposed than going off on a bit of a tangent in my original answer :D), here's my opinions:
1) My main opinion on this is that I dislike d. As a client consuming the API I would find it confusing. What does it even stand for anyway? data?
The other options look good. Columns is nice because it mirrors back to the user what they requested.
If you are doing pagination, then another option might be something like page or slice as it makes it clear to the client, that they are not receiving the entire contents of the collection.
{
"offset": 0,
"limit": 100,
"page" : [
...
]
}
2) TBH, I don't think it makes that much difference which way you go for this, however if it was me, I probably wouldn't bother sending back the envelope, as I don't think there is any need (see below) and why make the request structure any more complicated than it needs to be?
I think POSTing back the envelope would be odd. POST should let you add items into the collection, so why would the client need to post the envelope to do this?
PUTing the envelope back could make sense from a RESTful standpoint as it could be seen as updating metadata associated with the collection as a whole. I think it is worth thinking about the sort of meta data you will be exposing in the envelope. All the stuff I think would fit well in this envelope (like pagination, aggregations, search facets and similar meta data) is all read only, so it doesn't make sense for the client to send this back to the server. If you find yourself with a lot of data in the envelope that the client is able to mutate - then it could be a sign to break that data out into a separate resource with the list as a sub collection. Rubbish example:
/animals
{
"farmName": "farm",
"paging": {},
"animals": [
...
]
}
Could be broken up into:
/farm/1
{
"id": 1,
"farmName": "farm"
}
and
/farm/1/animals
{
"paging": {},
"animals": [
...
]
}
Note: Even with this split, you could still return both combined as a single response using something like Facebook's or LinkedIn's field expansion syntax. E.g. http://example.com/api/farm/1?field=animals.offset(0).limit(10)
In response, to your question about how the client should know what the JSON payload they are POSTing and PUTing should look like - this should be reflected in your API documentation. I'm not sure if there is a better tool for this, but Swagger provides a spec that allows you to document what your request bodies should look like using JSON Schema - check out this page for how to define your schemas and this page for how to reference them as a parameter of type body. Unfortunately, Swagger doesn't visualise the request bodies in it's fancy web UI yet, but it's is open source, so you could always add something to do this.
Original Answer
Check out William's comment in the discussion thread on that page - he suggests a way to avoid the exploit altogether which means you can safely use a JSON array at the root of your response and then you need not worry about either of you questions.
The exploit you link to relies on your API using a Cookie to authenticate a user's session - just use a query string parameter instead and you remove the exploit. It's probably worth doing this anyway since using Cookies for authentication on an API isn't very RESTful - some of your clients may not be web browsers and may not want to deal with cookies.
Why Does this fix work?
The exploit is a form of CSRF attack which relies on the attacker being able to add a script tag on his/her own page to a sensitive resource on your API.
<script src="http://mysite.com/api/columns"></script>
The victims web browser will send all Cookies stored under mysite.com to your server and to your servers this will look like a legitimate request - you will check the session_id cookie (or whatever your server-side framework calls the cookie) and see the user is authenticated. The request will look like this:
GET http://mysite.com/api/columns
Cookie: session_id=123456789;
If you change your API you ignore Cookies and use a session_id query string parameter instead, the attacker will have no way of tricking the victims web browser into sending the session_id to your API.
A valid request will now look like this:
GET http://mysite.com/api/columns?session_id=123456789
If using a JavaScript client to make the above request, you could get the session_id from a cookie. An attacker using JavaScript from another domain will not be able to do this, as you cannot get cookies for other domains (see here).
Now we have fixed the issue and are ignoring session_id cookies, the script tag on the attackers website will still send a similar request with a GET line like this:
GET http://mysite.com/api/columns
But your server will respond with a 403 Forbidden since the GET is missing the required session_id query string parameter.
What if I'm not authenticating users for this API?
If you are not authenticating users, then your data cannot be sensitive and anyone can call the URI. CSRF should be a non-issue since with no authentication, even if you prevent CSRF attacks, an attacker could just call your API server side to get your data and use it in anyway he/she wants.
I would go for 'd' because it clearly separates the 'envelope' of your resource from its content. This would also make it easier for consumers to parse your responses, as opposed to 'guessing' the name of the wrapping property of a given resource before being able to access what it holds.
I think you're talking about two different things:
POST request should be sent in application/x-www-form-urlencoded. Your response should basically mirror a GET if you choose to include a representation of the newly created resource in your reply. (not mandatory in HTTP).
PUTs should definitely be symmetric to GETs. The purpose of a PUT request is to replace an existing resource representation with another. It just makes sense to have both requests share the same conventions, doesn't it?
Go with 'Columns' because it is semantically meaningful. It helps to think of how JSON and XML could mirror each other.
If you would PUT the collection back, you might as well use the same media type (syntax, format, what you will call it.)