provide /me API endpoints while still providing basic endpoints matching the same routes - rest

I want to provide a me endpoint because not everyone should have access to all resources. The current logged in user should only have access to his own resources. So let's assume you would have a simple Todo REST API with an endpoint returning all tasks from a single user
GET /users/{username}/tasks
The current logged in user should not be able to get information about other users. A possible solution for this would be
GET /users/me/tasks
This has already been discussed here
Designing URI for current logged in user in REST applications
The problem is that I also want to keep the endpoint from above for development purposes (a private/hidden endpoint). Unfortunately both endpoints match the same route. So me could be the username.
I don't want to prevent a username called me with an if-statement like
if(username == "me")
throw new ConflictException("Username 'me' is forbidden");
I think this would be bad design. A possible solution would be to avoid embedding me in a resource and instead embed the resources in me endpoints. So instead of
GET /users/me/tasks
GET /users/me/orders
POST /users/me/tasks
PATCH /users/me/username
DELETE /users/me/tasks/{taskName}
I could remove the users resource and make me the initial base resource. As you might guess /users/:username extracts the username from the url parameter and /me extracts the username from the json web token but both endpoints run the same logic.
So when I want to keep private/hidden endpoints to fetch a user by username do I have to make me a separate resource? Or is there a way to keep me only as a replacement for the username parameter?
EDIT
I tried to create a simple route example. As you can see most of the endpoints of users and me are mirrored and only differ by the user identification (username as parameter or jwt payload). And for this sample only the me endpoints are accessible to everyone. Other endpoints are private / hidden.
users
GET / => get users => private
GET /:username => get user => private
GET /:username/tasks => get tasks from user => private
GET /:username/tasks/:taskName => get task from user => private
POST /:username/tasks => create user task => private
PATCH /:username/username => update username => private
DELETE /:username => delete user => private
DELETE /:username/tasks/:taskName => delete user task => private
tasks
GET / => get tasks => private
me
GET / => get current logged in user => public
GET /tasks => get tasks from current logged in user => public
GET /tasks/:taskName => get task from current logged in user => public
POST /tasks => create task for current logged in user => public
PATCH /username => update username => public
DELETE / => delete current logged in user => public
DELETE /tasks/:taskName => delete task from current logged in user => public

I think you are getting confused because your definitions are a bit tangled.
Here's the good news: REST doesn't care about the spelling conventions you use for your identifiers. So if it makes your life easy to have
GET /users/12345/tasks
GET /me/tasks
Then you can implement both of those, make sure that the access restrictions are correct, and off you go.
There's nothing wrong, from a REST perspective, about using
GET /users/12345/tasks
GET /users/me/tasks
The spellings of the target-uri are different, which means that from the perspective of a general-purpose client they identify different resources.
BUT... the routing implementation that you are using to implement your API may not allow you to easily distinguish these two cases. What you have effectively got here are two different matches for the same pattern, which requires some extra clever to remove the ambiguity; if your routing library/framework doesn't offer that, then you are going to have to shim it in yourself.
And, as you note, you've got a huge mess if the token "me" itself could match a real identifier.
REST doesn't have a concept of "base resource" - at least, not one that lines up with what you are thinking about. There's no inherent relationship between /users and /users/12345 from the REST perspective. Many server frameworks do treat request handling as a hierarchy of "resources", but again: that's an implementation detail of your particular server.
REST really only cares about your interface - that you understand HTTP requests in the standard way.
Which all brings us back to the good news; since REST doesn't care what spelling conventions you use, you are welcome to make any arbitrary choices you like... including whatever spelling convention makes your internal routing framework easy to work with.
So if your routing framework is telling you to create a different "initial base resource" to support your family of "me" endpoints, then just do that.

Related

ASP.NET Core 5 route redirection

We have an ASP.NET Core 5 Rest API where we have used a pretty simple route:
[Route("api/[controller]")]
The backend is multi-tenant, but tenant-selection has been handled by user credentials.
Now we wish to add the tenant to the path:
[Route("api/{tenant}/{subtenant}/[controller]")]
This makes cross-tenant queries simpler for tools like Excel / PowerQuery, which unfortunately tend to store credentials per url
The problem is to redirect all existing calls to the old route, to the new. We can assume that the missing pieces are available in the credentials (user-id is on form 'tenant/subtenant/username')
I had hope to simply intercept the route-parsing and fill in the tenant/subtenant route values, but have had not luck so far.
The closes thing so far is to have two Route-attributes, but that unfortunately messes up our Swagger documentation; every method will appear with and without the tenant path
If you want to transparently change the incoming path on a request, you can add a middleware to set Path to a new value, for example:
app.Use(async (context,next) =>
{
var newPath = // Logic to determine new path
// Rewrite and continue processing
context.Request.Path = newPath;
await next();
});
This should be placed in the pipeline after you can determine the tenant and before the routing happens.

REST - Updating partial data

I am currently programming a REST service and a website that mostly uses this REST service.
Model:
public class User {
private String realname;
private String username;
private String emailAddress;
private String password;
private Role role;
..
}
View:
One form to update
realname
email address
username
Another form to update the role
And a third form to change the password
.
Focussing on the first view, which pattern would be a good practice?
PUT /user/{userId}
imho not because the form contains only partial data (not role, not password). So it cannot send a whole user object.
PATCH /user/{userId}
may be ok. Is a good way to implement it like:
1) read current user entity
2)
if(source.getRealname() != null) // Check if field was set (partial update)
dest.setRealname(source.getRealname());
.. for all available fields
3) save dest
POST /user/{userId}/generalInformation
as summary for realname, email, username
.
Thank you!
One problem with this approach is that user cannot nullify optional fields since code is not applying the value if (input is empty and value) is null.
This might be ok for password or other required entity field but for example if you have an optional Note field then the user cannot "clean" the field.
Also, if you are using a plain FORM you cannot use PATCH method, only GET or POST.
If you are using Ajax you might be interested in JSON Merge Patch (easier) and/or JavaScript Object Notation (JSON) Patch (most complete); for an overview of the problems that one can find in partial updates and in using PATCH see also this page.
A point is that a form can only send empty or filled value, while a JSON object property can have three states: value (update), null (set null) and no-property (ignore).
An implementation I used with success is ZJSONPATCH
Focussing on the first view, which pattern would be a good practice?
My suggestion starts from a simple idea: how would you do this as web pages in HTML?
You probably start from a page that offers a view of the user, with hyperlinks like "Update profile", "Update role", "Change password". Clicking on update profile would load an html form, maybe with a bunch of default values already filled in. The operator would make changes, then submit the form, which would send a message to an endpoint that knows how to decode the message body and update the model.
The first two steps are "safe" -- the operator isn't proposing any changes. In the last step, the operator is proposing a change, so safe methods would not be appropriate.
HTML, as a hypermedia format, is limited to two methods (GET, POST), so we might see the browser do something like
GET /user/:id
GET /forms/updateGeneralInformation?:id
POST /updates/generalInformation/:id
There are lots of different spellings you can use, depending on how to prefer to organize your resources. The browser doesn't care, because it's just following links.
You have that same flexibility in your API. The first trick in the kit should always be "can I solve this with a new resource?".
Ian S Robinson observed: specialization and innovation depend on an open set. If you restrict yourself to a closed vocabulary of HTTP methods, then the open set you need to innovate needs to lie elsewhere: the RESTful approach is to use an open set of resources.
Update of a profile really does sound like an operation that should be idempotent, so you'd like to use PUT if you can. Is there anything wrong with:
GET /user/:id/generalInformation
PUT /user/:id/generalInformation
It's a write, it's idempotent, it's a complete replacement of the generalInformation resource, so the HTTP spec is happy.
Yes, changing the current representation of multiple resources with a single request is valid HTTP. In fact, this is one of the approaches described by RFC 7231
Partial content updates are possible by targeting a separately identified resource with state that overlaps a portion of the larger resource
If you don't like supporting multiple views of a resource and supporting PUT on each, you can apply the same heuristic ("add more resources") by introducing a command queue to handle changes to the underlying model.
GET /user/:id/generalInformation
PUT /changeRequests/:uuid
Up to you whether you want to represent all change requests as entries in the same collection, or having specialized collections of change requests for subsets of operations. Tomato, tomahto.

How to represent a read-only property in a REST Api

if you have a REST API that is hypermedia-driven (HATEOAS) you can easily change a client's behavior by including or omitting links in the response (_links). That enables a client to completely forget about testing permissions for the operations that are possible in the current state of a resource (the link to the operation is present or not).
Additionally you can leave out properties in the response if the current user doesn't have permission to see it.
That way authorization is done entirely on the server (and controls actions and properties that are eligible to execute/view).
But what if I want to a have a read-only property? It is no problem for the REST API to ignore the property if it is present in the request (_POST_ OR _PUT_). it just won't get saved. But how can a client distinguish between write and read-only properties to present the user appropriate controls (like a disabled input field in HTML)?
The goal is to never ever have the client request a user's permissions, but to have a completely resource driven client/frontend.
Any help is greatly appreciated :-)
If I misunderstood your question, I apologize upfront. With that being said...
But how can a client distinguish between write and read-only
properties to present the user appropriate controls (like a disabled
input field in HTML)
Well, there are multiple solutions to this. The simplest one I can personally think of is to make each property an object having a simple structure of something like:
...
someProperty: {
value: 'some value',
access: 'read-only'
},
someOtherProperty: {
value: 'some value',
access: 'write'
}
...
You can obviously get as creative as you want with how you represent the "access" level of the property (using enums, booleans, changing access to be isReadOnly or whatever).
After that, the person using the API now knows they are read-only or not. If they submit a "write" value for a "read-only" property as part of the POST payload, then they should expect nothing less than a 403 response.
Edit:
In case you can't alter the properties in this manner, there are a number of other ways you can still achieve this:
write documentation that explains what access each property has
create a route that the user can submit 1 or more properties to in order to receive a response that indicates the access level of each property (response: { propName: 'read-only', propName2: 'write', etc.)
Return a propertyAccess map as part of the response (mapping properties to access levels).
end of the day, you just need a way to map a property with an access level. however that's done depends on what your restrictions and requirements are for the api, what changes you can make, and what is acceptable to both your client(s) and the business requirements.

Play framework, Scala: authenticate User by Role

I've user roles: user, manager, admin. I need to authenticate them in controllers (methods). For example only admin can delete (now it looks like this, need to change that only admin should have permission):
def deleteBook(id: Int) = DBAction {
findById(id) match {
case Some(entity) => {
books.filter(_.id === id).delete
Ok("")
}
case None => Ok("")
}
}
I've many controllers and methods. I need to authenticate before process request (for example deleting book). My routes file contains:
...
DELETE /books/:id #controllers.Book.deleteBook(id: Int)
...
Some routes are only accessible to admin and manager. Some are for all types of users.
I'm currently seeing deadbolt2scala authorization module for play.
Can you recommend best way to authenticate multirole users in playframework scala?
I've managed to do this by using StackableControllers provided by https://github.com/t2v/stackable-controller
Basically, I use a basic access control list provided by my application.conf. I start by checking if there is a user in my request. If there is one, I can check if he has sufficient access rights to perform the action.
Such a feature may be implemented using BodyParser composition too. I've never done that, though, so someone else's advice may be better for you.

REST Url ID Placement for Resources with Collections

Is this a good structure for REST URLs?
Assuming:
GET /account <- get list of accounts
GET /account/1234 <- get account 1234
etc.
If the account resource has a collection that I want to interface, is this a good idea?
GET /account/1234/note <- get notes for account 1234
POST /account/1234/note <- add note to account 1234
DELETE /account/1234/note/321 <- delete note 321 on account 1234
Especially that last one gives me pause; typically I wouldn't require both the entity ID and the parent ID when deleting.
Or maybe something like this would be better?
GET /account-note/1234 <- get notes for account 1234
POST /account-note/1234 <- add note to account 1234
DELETE /account-note/321 <- delete note 321 on account 1234 (b/c note 321 is on account 1234)
But then I'd end up with a pretty shallow URL set.
Thanks
There's nothing wrong with your first api. In large part, the idea of the RESTful interface is to go with the natural tree structure of the web, and your first approach is in keeping with that. It's also going to be a structure that does the API's job of abstracting away implicit constraints of your datastore, because the second approach implicitly assumes that the id of note is globally unique. This may be true now, and will probably remain true, but it's also exactly the kind of bug that suddenly appears with disastrous consequences when, down the line, some kind of major db change happens.
I'd go with your first scheme. It's a familiar rest pattern, it's intuitive, and it's not going to blow up in a weird way down the line. Also, in response to #Corwin01 minimize the query params--they're not so RESTful.
I referenced this question in my comments on another question and between the feedback I got there and my own research this is what I've come up with.
Firstly, the question is sort of flawed. RESTful APIs, or to use the perferable term Hypermedia APIs should include the urls of related actions so that the interface is discoverable and changes won't break existing clients, therefore the exact structure has significantly less importance than I was placing on it, these can be changed later.
Secondly, the note in the example will be retrieved as part of an account query, maybe something like this:
<account>
...
<notes>
<note>
...
<link href="/account-note/123" rel="note">
</note>
</notes>
</account>
The client will never be assembling urls to the account on their own, the client will use the link provided. Since the note ID is globally unique in this case, there is no need to include the key twice. Hence the answer to the question is no, the first example is not a good REST url structure, the second one is better. (Although still maybe not the best...)
Mind you, my experience is with JAX-RS and Jersey, so I'm not sure what the exact differences are.
However, this is what I would do:
#GET
#Path ("/account/note/{id}")
public void displayNotes(#PathParam ("accountId") String accountId)
{
//do stuff
}
#POST
#Path ("/account/note")
public void addNote(#FormParam ("accountId") String accountId)
{
//do stuff
}
#POST
#Path ("/account/note/delete")
public void deleteNote(#FormParam ("accountId") String accountId, #FormParam ("noteId") String noteId)
{
//do stuff
}
This way, you don't have cluttered and confusing URLs that the user doesn't need to see anyways, especially if the user tries to navigate there on their own. Which is ok for displaying the accounts, but would confuse them for the URLs that POST, since they would get a 404 and not understand why.
Keep it simple, and just user #FormParams since the user doesn't need to see that anyways.