The background first:
I have an application where a logged-in user(employee) X can see a list of all other users (employees). If the logged-in user X is a manager (their designation), then they can also edit certain attributes of the users they manage. For example, the location, designation, and the department of the user being edited. It should be noted X can edit only those employees who report to him/her, which means there are users which X is not allowed to edit.
When X clicks on a user to edit it, they navigate to a page like http:myapp.com/dashboard/editUser/<ID_OF_THE_USER_BEING_EDITED>
Obviously, X can get smart and manually edit the URL and put in the id of a user they are NOT allowed to edit, so before loading the edit form I need to check whether X has the authorization to edit user Y. if X is authorized to do so, then that page displays a form (with the current attributes of the users pre-filled in the appropriate fields) to edit the user. Else, I display an 'Access Denied' kind of message.
Right now I have created a very badly named temporary endpoint (/api/v1/maybe_edit_user/?jwt=<TOKEN>&userId=<USER_BEING_EDITED>
).
This grotesque-looking endpoint does 2 things:
- It extracts the currently logged-in user from the token, and checks whether it has the required access level to edit the user (passed through the GET parameter
userId
) - If yes, then it returns the current attributes (name, email, location, designation, and other stuff) in the response, which is then pre-filled in appropriate fields when the form is displayed.
Once X submits the form, a PUT request is sent to another endpoint (/api/v1/users/<USER_ID_OF_Y>
PUT) and the user Y is updated.
While this works, I don't find it attractive. I am trying to learn to write better, cleaner, and more organized code that is compliant with the standards.
The best practices for REST suggest that all endpoints should be nouns. My endpoint, on the other hand, is not even a simple verb. It's a god-forsaken phrase at the very minimum.
So, the questions here are:
- How should I name my endpoint.
- Should I use a single endpoint to check for permission, AND fetching the attributes of the user being edited, like I am doing right now? Or should I break them into 2 separate endpoints?
CodePudding user response:
The fact that there is an access control list is an unrelated concern; ignore it.
Resource identifier identify resources. Resources are generalizations of documents.
You want an identifier that is consistent with the production rules of RFC 3986, and it is often convenient (but not required) to choose spellings that enable leverage of URI Templates (RFC 6570), but otherwise the machines don't care.
That means you can choose a spelling that makes things easier for humans; you get to choose which humans get priority here.
it returns the current attributes (name, email, location, designation, and other stuff) in the response
That's your hint as to what the document is; some sort of digest of Bob's... profile? employee record? dossier? that is apparently optimized for use in this specific kind of form.
So the identifier could be as simple as
/this-specific-kind-of-form/source-data/Bob
and a request might look like
GET /this-specific-kind-of-form/source-data/Bob HTTP/1.1
Authorization: Bearer <token>
The implementation looks largely like your sketch - verify the token, compare the claims to those that are required, and return either the resource or some flavor of Client Error (4xx).
The best practices for REST suggest that all endpoints should be nouns.
Don't read too much into that.
Notice that all of the following resource identifiers work:
- https://www.merriam-webster.com/dictionary/get
- https://www.merriam-webster.com/dictionary/post
- https://www.merriam-webster.com/dictionary/put
- https://www.merriam-webster.com/dictionary/patch
- https://www.merriam-webster.com/dictionary/delete
You can click on any of those links, and your browser will create the correct HTTP request, and the server will do the expected thing.