Say I'm creating a journaling application and I want users to be able to post entries to their journals.
I do not intend to ever allow a user (even a moderator) to post an entry in someone else's journal.
That said, are there any arguments for exposing the account or journal id in my endpoint path?
I would think that POST api/journals/postEntry would be sufficient as I can determine the user via access token or JWT token.
Can anyone think of arguments for providing the journalId in the path? EX: POST api/journals/{user journalId}/postEntry
Can anyone think of arguments for providing the journalId in the path? EX: POST api/journals/{user journalId}/postEntry
Short answer: it's a violation of the uniform interface constraint.
See Fielding, 2000.
What you are doing, in effect, is creating this little corner of the world where, instead of using the target-uri to identify a resource, you are instead using target-uri + token.
Which means that your thing doesn't use the semantics that the general purpose components in the world are expecting.
For example, when I copy the URI out of my user agent, and share it with someone else, that other person doesn't get the result I expect -- they end up looking at their view, not mine.
The fact that we can stick a URI in an email message and have it just work for the person reading the email is a really big piece in the adoption story.
Furthermore, the cache constraint in REST rather depends on being able to use the identifier as the primary cache key. So your bespoke identity mechanism has the potential to mess up caching.
IN PRACTICE: you are using HTTP, and HTTP has caching rules that prohibit sharing authenticated requests. So the caching issues mentioned above are purely theoretical.
Alternatives you might consider
You could arrange for /api/journals/postEntry to redirect to /api/journals/{userJournalId}/postEntry
You could use the Content-Location header to indicate that there is a more specific identifier for the current representation.
You can use the canonical link relation to help clients navigate to the preferred resource from the alternatives.
Related
My HTTP API requires the frontend to pass an accountId on API calls due to the fact we support admin users who are not tied to a single account and could be querying any account.
Initially I implemented this as a header the issue here is that caching would not work.
The current implementation looks like api.com/endpoint?accountId=123 whilst this works well - I would like to understand if this is the correct approach when implementing a RESTful HTTP API.
UPDATE:
Based on a comment - this is for GET
IMO, you did things "the right way" (TM) by putting this information in a HTTP header -- that seems to be the correct place for this to live. However your caching system currently doesn't care about HTTP headers, so that leaves you with a practical problem (which doesn't really care about "the right way"). So...
Based on that, it sounds like you have two options:
Fix your caching to include specific headers as part of the cache key, or
Add relevant information to the URL for caching purposes
I'd suggest (1) where you update the cache key to be a hash of the URL + other relevant information that would result in a different result (in this case, the HTTP header including the account ID or session information). This allows you to keep putting information in the right place while also not causing issues for cached pages.
Of course this might not be possible, so the only practical solution I can offer you is (2) where you pull stuff into the URL in order to support caching. I think this is an anti-pattern, but it will get the job done.
Make-up scenario:
Let's say I am building a RESTful Web API backend for managing the payment plans for members:
It's for members so you would have to register with us. Each member would have a member ID internally.
There are various payment plans: 0% interest for 6 months, 0% interest for 12 months, etc. Each payment plan would have an ID internally.
The relationship between member and payment plan is many-to-many.
Each member also would have 1 active plan at a time. You can change it, but there is only 1 active plan allowed for a member.
Now if I want to design an API endpoint to return the information about the member active payment plan, I would normally do something like:
/members/{member-id}/plans/active
I understand that it might be a bad idea to put state on the URI (I had a separate question for that matter), but please bear with me.
Now here is the tricky part: the company's policy states that I can't have the member ID in the URI. They will have some kind of tokens in HTTP header, which is required in order to access the RESTful API endpoints, that contains the member ID.
My API application, which is ASP.NET Core Web API by the way, has no problem creating a filter to parse that token and transform it into member ID, in the code. It's just that my API URIs can't have the member ID anymore.
How would you design the URI in this case?
Without the member ID on the URI, mine would look like
/plans/active
And the data now would be all driven/filtered by that member ID, securely inside the API backend. Is this normal?
the data now would be all driven/filtered by that member ID, securely inside the API backend. Is this normal?
It sounds to me as though things are going sideways; as though people don't understand REST, or that people don't understand that what they are trying to achieve isn't a good fit for REST.
In order to obtain a uniform interface, multiple architectural constraints are needed to guide the behavior of components. REST is defined by four interface constraints: identification of resources.... -- Fielding, 2000
REST uses a resource identifier to identify the particular resource involved in an interaction between components. REST connectors provide a generic interface for accessing and manipulating the value set of a resource, regardless of how the membership function is defined or the type of software that is handling the request. The naming authority that assigned the resource identifier, making it possible to reference the resource, is responsible for maintaining the semantic validity of the mapping over time (i.e., ensuring that the membership function does not change). -- Fielding, 2000
The web works on the shared understanding that uniform resource identifiers identify resources. The URI is the key of the key/value store. When you start moving identifying information into other parts of the request, then you are opting out of the "uniform interface" that is shared by everyone else. This puts interop at risk.
On the other hand, much of the web also assumes that identifiers are published, and there isn't in general a lot of discipline to restrict the copying of them. So you certainly don't want secrets and/or sensitive information included.
The answer in REST is to use another layer of indirection. The rule is that we should be using a URI, and each identifier should map to one resource. But there's no rule that says that the spelling of the URI must match the semantics of the resource.
In other words: URL shorteners work!
GET /99bfb1e3-89a4-4a44-a6d7-0e70c209f447 HTTP/1.1
As far as REST is concerned, that's a perfectly valid request, with an entirely satisfactory identifier. As long as your server understands how to find the secrets using that key, then that's fine.
Of course, you could add semantic information to the URI that isn't sensitive, to help the humans orient to the context
GET /members/99bfb1e3-89a4-4a44-a6d7-0e70c209f447/plans/active HTTP/1.1
GET /members/plans/active/99bfb1e3-89a4-4a44-a6d7-0e70c209f447 HTTP/1.1
GET /members/plans/active?99bfb1e3-89a4-4a44-a6d7-0e70c209f447 HTTP/1.1
These are all also fine (again, assuming that you can use the information provided to discover the sensitive information you need to produce/modify the corresponding resource).
On the other hand, if your organization's concerns are related to leaking the identifier itself... then somebody with seniority should really be challenging the assumption that REST/HTTP is the right answer to the problem.
As your deviate further from the "standard" for HTTP messages, you increase the risk that some general purpose component isn't going to understand what is going on, and if that results in significant loss of property, your lawyers aren't going to be happy.
In my opinion this is pretty normal. This is usually the case when you are using a JWT token for authentication for example. The token not only authenticates the user but also contains relevant information about it.
In these cases, you will also see APIs with that kind of endpoints without any information about the user (like an ID or something) explicitly in the path.
Just a suggestion or a point of view from my side, I would actually keep the members part in the path: /members/plans/active.
I'm building an API where a logged in user can see his or her information. The user is also able to change its information. Only the user should be able to see and change their own info. Is it better to use the following routes
/me
/me/items
or (with policies)
/users/1
/users/1/items
/users/1 is marginally better than /me, but in practice it probably doesn't matter at all.
At the high level, REST doesn't care about URI spellings at all. General-purpose components treat the URI as opaque; only the origin server has any business trying to extract semantic information from the identifier.
From a design perspective, /me is somewhat vulnerable to the fact that you are combining two different concerns; "who is this resource about?" "who is allowed access?". It happens that today "Bob" is the only person authorized to read the "Bob" resource, but there's no particular reason that those two ideas will always be coupled together.
From the perspective of REST, having the same resource identifier mean different things depending on other header information could make the caching of representations problematic, in that you force the caches to become a lot smarter about deciding when a representation can be re-used.
HTTP solves some of this problem via the Vary header, which allows the origin server to describe to general purpose components which parts of the HTTP request might change the correct representation to use.
But in practice, even that is irrelevant, because HTTP doesn't permit shared caches to store a response to a request with an Authorization header field.
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.
In terms of RESTful and stateless it's pretty legal to have resource like
/users/123
But, the question is: is it legal to have resource that omits user id and assumes that it's implicitly resolved on the server from the user session? For example:
/loggedUser
That resource would point to /users/123 when user with identifier 123 is authorized.
Picking a resource locator
Using /me, /users/me, /users/myself, /users/current or similar URIs to identify a resource that corresponds to the authenticated user is perfectly fine from a REST perspective. According to Roy Thomas Fielding's dissertation, any information that can be named can be a resource:
5.2.1.1 Resources and Resource Identifiers
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. [...]
When using the URIs mentioned above, you have an identifier for the authenticated user and it will always identify the concept of an authenticated user, regardless of which user is authenticated.
The stateless constraint
The stateless constraint is not related to how your resources are identified. The stateless constraint is about not storing any session state on server side. In this approach, each request from client to server must contain all the necessary information to be understood by the server.
See que following quote from Fielding's dissertation:
5.1.3 Stateless
[...] each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]
When targeting protected resources that require authentication, for example, every request must contain all necessary data to be properly authenticated/authorized.
A similar question has been answered here and here.
It is OK as long as you use only the data from request (HTTP Headers in your case). In other words, this may work only for users that pass authentication.
Yes.
It is very common for ReST services to make assumption about authorization context.
Though making such a decision will limit usability of that route for users other than the logged on user. For example an admin might need to use that service for a specific user.
A ReST endpoint may even use Claims that exist in the Authorization context. for example return different data for a user that has logged in using certain mechanism.
of all HTTP headers, there are some that are probably not good to be used to tailor the ReST response. for example I will not use the 'referer'.
Make sure you check for any caching strategy you may have before making such design decisions.
It is perfectly legal as long as you keep it stateless. That is, you infer the current user from a security context provided with the HTTP request, usually a token of some kind.
For example, you perform a GET /current-user with an Authentication header containing a JWT token. The server can get most of the user info of the current user from the JWT token and complete with data from the database and retrieve it back to the caller.
I'd also recommend not to use camel case in URIs. It can be a nightmare for devs and some servers are case insensitive.
Beware, if you are holding a server user session, as you imply in your question, your API is already stateful.
As #n00b says, REST isn't a formal standard - and that's probably a good thing.
The original definition comes from Roy Fielding's dissertation. - so if you're doing the things Roy recommends, your design is RESTful. There are a few other things people have added to that - for instance, the Richardson Maturity Model is pretty commonly accepted. There are a few public "standards" documents on the web, e.g. Microsoft's version. I don't think they address this question directly, though.
So, it's up to you - but for what it's worth...
I believe APIs should be consistent and predictable. If I am asking for information about a user, I don't really like that there are two ways of doing it - one by ID, and one using a magic identifier for the current user. I also don't like the idea of introducing the concept of state into the API - by saying "there's an conceptual entity in your API called current user", you are introducing the concept of statefulness, even if you use HTTP headers to manage that.
So, if your RESTful API is designed for use by client application, I think it's reasonable to ask that client to manage state, and carry around the ID for the current user. This also makes your GET requests consistently cacheable - you can theoretically cache /users/123, but you cannot cache /loggedUser.
I believe there is a logical difference with your authentication and authorization action (I've logged in, proven who I am, and therefore got access to specific resources on the system), versus "I am user 123".
The reason you might disagree with this is that it makes your API harder to discover by human beings - someone who is trying to figure out how to get information about the current user has to log in, and then remember their user ID.