REST Hypermedia: Should the actions be filtered based on the user's permissions? - rest

According to Roy Fielding's Hypermedia As The Engine of Application State (HATEOAS), each resource should be accompagnied with a list of actions (or links) that can be done on that resource.
If the actions are included in the entity (as apposed to using the links attribute of Json-Schema), how do I tell the user-agent that a specific option is not available to the authenticated user?
The backend could do the filtering, but then the same resource URL could have different representations depending on the authenticated user. And this does not seem REST-friendly or caching friendly.
The other option is to leave all links, and let the user-agent receive a 403 Forbidden when the action is not available to the authenticated user. This can be annoying to the user.
How to inform the user-agent on the available actions when those can change depending on the authenticated user, while remaining REST-friendly?

You are correct. Creating representations that vary based on user permission is not particularly cache friendly. Is it possible to classify permission variants into just a few categories? e.g. resource-low-security, resource-medium-security resource-high-security
Sometimes this approach is possible, sometimes it is not. The other aspect to consider is whether caching is critical for this particular resource. Maybe it is now?
Also, it is not necessary to wait until the user clicks on a link to find out if the user has the permissions to follow it. The client could perform an OPTIONS request on links in the background to discover which links are available and dynamically disable the links that are not accessible.
There is no single answer to this problem. Different solutions will work in different cases depending on the requirements.

Consider that a REST API is a website for a robot to browse.
Do websites return HTML resources (pages) containing links that you're not permitted to see?
Whether it does or not, it doesn't change how "hypermediary" the website is.
but then the same resource URL could have different representations depending on the authenticated user
Consider the same about the homepage of a website. A resource is conceptual, the home page is the concept, what it looks like changes.
How does the web deal with the caching of pages for logged-in and logged-out views?
The first way is to bar caching of those resources; not everything must be cachable, the constraint is simply that resources can be labeled accordingly.
The second is using control semantics, or headers if you're using HTTP for your REST API.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary

Related

Specific action on entities (ban, unban, make current, change status) in my RESTful API design?

In my current API design I'm following these rules:
PATCH is used to partially update a resource
POST is used to create resources
PUT isn't used at all
I need to expose specific update actions (not exposed as PATCH, for security reasons), i.e. change the status of an order to "confirmed", "partially confirmed" or "refused".
I'm struggling on:
POST /carts/:id/:status and DELETE /carts/:id/:status: seems wrong as POST should create resources
PATCH /carts/:id/:status: seems wrong because the payload would be empty
Which one would be the most consistent and appropriate with the above API design? Do I have other options?
It may help to review Webber 2011
You have to learn to use HTTP to trigger business activity as a side effect of moving documents around the network.
I need to expose specific update actions (not exposed as PATCH, for security reasons), i.e. change the status of an order to "confirmed", "partially confirmed" or "refused".
How would you do this on the Web?
The most common answer would look something like this: you would have a web page for "the order"; and that page would include hyperlinks to some forms - it might be a simple "change order status form", or you might have different forms for each change. When we submit the form, the browser would create from form data and metadata an HTTP POST request, targeting whatever resource was specified by the form.
Important takeaways
It is okay to use POST.
The server can choose whatever URI it likes as the form target.
One convenient choice would be to use the URI for "the order" web page, because that allows you to take advantage of the general purpose cache invalidation defined by the HTTP standard.
You can, of course, use PUT or PATCH semantics instead, if you like. The primary difference is that these methods use remote authoring semantics - they are the HTTP methods we would use if we were trying to edit a web page.
To change the status of an order, it might go roughly like this: you would GET the current web page, and edit your local copy to change the status information. Then you would use HTTP to save your copy of the web page on the server:
For PUT, the payload of the request would be the entire web page with your edits.
For PATCH, the payload of the request would be a patch document describing just your edits.
The server would then need to either accept your request (applying your changes to its copy of the web page) or reject them (for example, if those changes are not consistent with business policy).
Which one would be the most consistent and appropriate with the above API design? Do I have other options?
You'll probably have an easier time if you relax the restriction that POST is only used to create resources.
Remember, the world wide web is the reference implementation of the REST architectural style, and it was catastrophically successful. Yet PUT and PATCH were used only rarely -- almost all information was carried to web servers using POST semantics.
But if must limit yourself to these rules for non technical reasons, then you might consider a resource model where information is sent to the business by creating new resources on the web server. In other words, instead of changing the status of the order by editing the order web page, you could instead create a new "change the status of the order" document on the server.
(Technically, you could use any of POST/PUT/PATCH to create the new document, but POST is normal and consistent with your constraints, so it seems a reasonable starting point).

Can I use redirects in my RESTful API to alias user specific content

I have a typical RESTful API that consist of a tree of resources that are available to everyone. They are structured like this:
/api
/api/games
/api/games/101
/api/games/101/boards
/api/games/101/boards/201
These all include public information and nothing user specific so that the responses can be cached effectively until the resources change.
Now I want to allow different actions to different users.
For example: User Alice can post boards in game 101 but Bob can not.
So in the response from /api/games/101 I have, among other information, a URL to available actions.
This url is /api/games/101/actions for all users, so the response /api/games/101 can be cached.
Now /api/games/101/actions will redirect to a user specific URL where user specific actions are defined. either /api/games/101/actions/alice or /api/games/101/actions/bob depending on which user is authenticated in the request.
My question is if this i a good ide? Will there be a problem with caching in the browser if I change the authenticated user, since this is a per-authenticated-user cache, asuming the client is a html-webapp.
My question is if this is a good idea?
Yes it is a good idea to have different resources (and different identifiers) for information that is different. Although given the constraints on private caches defined by RFC 7234, it may not make a useful difference.
Having different resources for each role might be more manageable, in the long term, than different resources for each authenticated user.
Will there be a problem with caching in the browser if I change the authenticated user, since this is a per-authenticated-user cache, assuming the client is a html-webapp.
Private caches are permitted to re-use responses to authenticated requests, so there's always then potential for a problem when Bob and Alice share a web browser, but don't necessarily have access to the same resources.

REST API design for resource modification: catch all POST vs multiple endpoints

I'm trying to figure out best or common practices for API design.
My concern is basically this:
PUT /users/:id
In my view this endpoint could by used for a wide array of functions.
I would use it to change the user name or profile, but what about ex, resetting a password?
From a "model" point of view, that could be flag, a property of the user, so it would "work" to send a modification.
But I would expect more something like
POST /users/:id/reset_password
But that means that almost for each modification I could create a different endpoint according to the meaning of the modification, i.e
POST /users/:id/enable
POST /users/:id/birthday
...
or even
GET /user/:id/birthday
compared to simply
GET /users/:id
So basically I don't understand when to stop using a single POST/GET and creating instead different endpoints.
It looks to me as a simple matter of choice, I just want to know if there is some standard way of doing this or some guideline. After reading and looking at example I'm still not really sure.
Disclaimer: In a lot of cases, people ask about REST when what they really want is an HTTP compliant RPC design with pretty URLs. In what follows, I'm answering about REST.
In my view this endpoint could by used for a wide array of functions. I would use it to change the user name or profile, but what about ex, resetting a password?
Sure, why not?
I don't understand when to stop using a single POST/GET and creating instead different endpoints.
A really good starting point is Jim Webber's talk Domain Driven Design for RESTful systems.
First key idea - your resources are not your domain model entities. Your REST API is really a facade in front of your domain model, which supports the illusion that you are just a website.
So your resources are analogous to documents that represent information. The URI identifies the document.
Second key idea - that URI is used by clients to cache representations of the resource, so that we don't need to send requests back to the server all the time. Instead, we have built into HTTP a bunch of standard ways for communicating caching meta data from the server to the client.
Critical to that is the rule for cache invalidation: a successful unsafe request invalidates previously cached representations of the same resource (ie, the same URI).
So the general rule is, if the client is going to do something that will modify a resource they have already cached, then we want the modification request to go to that same URI.
Your REST API is a facade to make your domain model look like a web site. So if we think about how we might build a web site to do the same thing, it can give us insights to how we arrange our resources.
So to borrow your example, we might have a web page representation of the user. If we were going to allow the client to modify that page, then we might think through a bunch of use cases (enable, change birthday, change name, reset password). For each of these supported cases, we would have a link to a task-specific form. Each of those forms would have fields allowing the client to describe the change, and a url in the form action to decide where the form gets submitted.
Since what the client is trying to achieve is to modify the profile page itself, we would have each of those forms submit back to the profile page URI, so that the client would know to invalidate the previously cached representations if the request were successful.
So your resource identifiers might look like:
/users/:id
/users/:id/forms/enable
/users/:id/forms/changeName
/users/:id/forms/changeBirthday
/users/:id/forms/resetPassword
Where each of the forms submits its information to /users/:id.
That does mean, in your implementation, you are probably going to end up with a lot of different requests routed to the same handler, and so you may need to disambiguate them there.

How to make initial request for nested resource from self describing REST API

Background:
I have a single page application that pulls data from a REST API. The API is designed such that the only URL necessary is the API root, ie https://example.com/api which provides URLs for other resources so that the client doesn't need to have any knowledge of how they are constructed.
API Design
The API has three main classes of data:
Module: Top level container
Category: A sub-container in a specific module
Resource: An item in a category
SPA Design
The app consuming the API has views for listing modules, viewing a particular module's details, and viewing a particular resource. The way the app works is it keeps all loaded data in a store. This store is persistent until the page is closed/refreshed.
The Problem:
My question is, if the user has navigated to a resource's detail view (example.com/resources/1/) and then they refresh the page, how do I load that particular resource without knowing its URL for the API?
Potential Solutions:
Hardcode URLs
Hardcoding the URLs would be fairly straightforward since I control both the API and the client, but I would really prefer to stick to a self describing API where the client doesn't need to know about the URLs.
Recursive Fetch
I could fetch the data recursively. For example, if the user requests a Resource with a particular ID, I could perform the following steps.
Fetch all the modules.
For each module, fetch its categories
Find the category that contains the requested resource and fetch the requested resource's details.
My concern with this is that I would be making a lot of unnecessary requests. If we have 100 modules but the user is only ever going to view 1 of them, we still make 100 requests to get the categories in each module.
Descriptive URLs
If I nested URLs like example.com/modules/123/categories/456/resources/789/, then I could do 3 simple lookups since I could avoid searching through the received data. The issue with this approach is that the URLs quickly become unwieldy, especially if I also wanted to include a slug for each resource. However, since this approach allows me to avoid hardcoding URLs and avoid making unnecessary network requests, it is currently my preferred option.
Notes:
I control both the client application and the API, so I can make changes in either place.
I am open to redesigning the API if necessary
Any ideas for how to address this issue would by greatly appreciated.
Expanding on my comment in an answer.
I think this is a very common problem and one I've struggled with myself. I don't think Nicholas Shanks's answer truly solves this.
This section in particular I take some issues with:
The user reloading example.com/resources/1/ is simply re-affirming the current application state, and the client does not need to do any API traversal to get back here.
Your client application should know the current URL, but that URL is saved on the client machine (in RAM, or disk cache, or a history file, etc.)
The implication I take from this, is that urls on your application are only valid for the life-time of the history file or disk cache, and cannot be shared with other users.
If that is good enough for your use-case, then this is probably the simplest, but I feel that there's a lot of cases where this is not true. The most obvious one indeed being the ability to share urls from the frontend-application.
To solve this, I would sum the issue up as:
You need to be able to statelessly map a url from a frontend to an API
The simplest, but incorrect way might simply be to map a API url such as:
http://api.example.org/resources/1
Directly to url such as:
http://frontend.example.org/resources/1
The issue I have with this, is that there's an implication that /resource/1 is taken from the frontend url and just added on to the api url. This is not something we're supposed to do, because it means we can't really evolve this api. If the server decides to link to a different server for example, the urls break.
Another option is that you generate uris such as:
http://frontend.example.org/http://api.example.org/resources/1
http://frontend.example.org/?uri=http://api.example.org/resources/1
I personally don't think this is too crazy. It does mean that the frontend needs to be able to load that uri and figure out what 'view' to load for the backend uri.
A third possibility is that you add another api that can:
Generate short strings that the frontend can use as unique ids (http://frontend.example.org/[short-string])
This api would return some document to the frontend that informs what view to load and what the (last known) API uri was.
None of these ideas sound super great to me. I want a better solution to this problem, but these are things I came up with as I was contemplating this.
Super curious if there's better ideas out there!
The current URL that the user is viewing, and the steps it took to get to the current place, are both application state (in the HATEOAS sense).
The user reloading example.com/resources/1/ is simply re-affirming the current application state, and the client does not need to do any API traversal to get back here.
Your client application should know the current URL, but that URL is saved on the client machine (in RAM, or disk cache, or a history file, etc.)
The starting point of the API is (well, can be) compiled-in to your client. Commpiled-in URLs are what couple the client to the server, not URLs that the user has visited during use of the client, including the current URL.
Your question, "For example, if the user requests a Resource with a particular ID", indicates that you have not grasped the decoupling that HATEOAS provides.
The user NEVER asks for a resource with such-and-such an ID. The user can click a link to get a query form, and then the server provides a form that generates requests to /collection/{id}. (In HTML, this is only possible for query strings, not path components, but other hypermedia formats don't have this limitation).
When the user submits the form with the ID number in the field, the client can build the request URL from the data supplied by the server+user.

Authorization and the query string in REST API design

We have a design where a user has access to products, but only in a certain category.
A superuser can list all products in all categories with a simple GET request, such as GET /products.
Simple filtering already exists via the query string, so the superuser can already restrict his search to category N by requesting GET /products?category=N.
Say that user X is authenticated, and user X has access to products with category of 3.
Should an API server:
mandate that the user pass the filter for the appropriate category -- ie require GET /products?filter=3, and GET /products would fail with 403 Forbidden? -- or
expect a simple GET /products and silently filter the results to those that the user is authorized to access?
expect a simple GET /products and silently filter the results to those that the user is authorized to access?
Changing the representation of a resource depending on which user is looking at it strikes me was a Bad Idea [tm].
Consider, for instance, the use case where a uri gets shared between two users. They each navigate to the "same" resource, but get back representations of two different entites.
Remember - here's what Fielding had to say about resources
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.
Now, there are conceptual mappings which depend on the perspective of the user (e.g. "today's weather in my city"). But I'm a lot more comfortable addressing those by delegating the work to another resource (Moved Temporarily to "today's weather in Camelot") than I am in treating the authorization credentials as a hidden part of the resource identifier.
If consumers of your api are arriving at this resource by following a link, then 403 Forbidden on the unfiltered spelling is fine. On the other hand, if consumers are supposed to be bookmarking this URI, then implementing it as a redirecting dispatcher may make more sense.
The redirecting approach is consistent with remarks made by Fielding in a conversation about content negotiation on the rest-discuss list in 2006
In general, I avoid content negotiation without redirects like the
plague because of its effect on caching.
E.g., if you follow a link to
http://www.day.com/
then the site will redirect according to the user's preference to one of
http://www.day.com/site/en/index.html
http://www.day.com/site/de/index.html
Both of the solutions are perfectly valid. You can always hide things when the user does not have the permission to see them. This means, that you can display a filtered representation of /products by the actual user, or you can hide the /products resource and give link only to the /products?filter=3 resource. I don't think there is a best practice here, since both solutions are easy to implement.
#VoiceOfUnreason:
Apparently you did not read Fielding's work carefully enough.
Changing the representation of a resource depending on which user is
looking at it strikes me was a Bad Idea [tm].
The representation depends on the whole request, not just on the GET /resource part. The Authorization header is part of the HTTP request as well. So changing the representation depending on the Authorization header is valid in REST. It is just the same as changing the representation depending on the Accept header. Or do you say that we should serve XML even if somebody requests for JSON? It is a huge mistake to think that a single resource can have only a single representation. Another mistake to return a broken link to the client and let them waste resources by sending pointless HTTP messages...
Consider, for instance, the use case where a uri gets shared between
two users. They each navigate to the "same" resource, but get back
representations of two different entites.
REST is for machine to machine communication and not for human to machine communication! The browser is not a REST client. Or did you mean that a facebook bot will share the link with a google crawler? Such a nonsense...