Hello, Hashnode community.
I have been working on REST APIs on NODE.JS for a while now, but recently I came across an article of endpoints naming conventions. It made more sense to me until I got stuck at this point.
So, I have a challenges/ route and it has sub-routes.
I am using:
POST - challenges/ for creating a new challenge.
GET - challenges/:id for getting the details of a challenge.
GET - challenges/current for getting the list of current challenges.
And here I am stuck because this creates a conflict between the last 2 routes.
So, what should be a better naming convention here?
Secondly, I am using JWT for managing sessions. The payload of JWT also contains a userId.
Now, JWT verification is used as a middleware, so I have userId available in res.locals.userId, but now, let's say I want to see my profile details, and I hit this API, GET -users/:id, then I am getting 2 IDs, can be same and can be different, if user views someone else's profile.
It gets even more tricky with edit profile, since, someone can edit the :id parameter and update someone else's profile using the route PATCH - users/:id. But I also have userId from JWT token.
So, which one should I use? JWT or the one from query parameter?
Thank you.
For your first problem, route handling always goes by regex sequence so place /challenges/current first and then keep /challenges/:id, so that the control comes to :id route only if it fails for current regex match.
For second problem, JWT and REST are not related conceptually so expecting userId in JWT is for your logic and expecting :id in the route is the REST standard so expect both and before you proceed with the actual logic with JWT inside middleware, first you verify if user-id passed inside JWT and route are same otherwise you respond with 403-forbidden access.
Some of the routes you are using are not REST compliant. Remember, REST stands for Representational State Transfer; if you have static routes like
/challenges/current,currentisn't exactly a state: it's a property.You need to change it. Use a generic route scheme:
GET /challenges- Get all the challenges;GET /challenges/:id- Get a specific challenge by an ID.Then, to get the currently open or active challenges, you can add a query filter:
GET /challenges?filter=activeorGET /challenges?filter=openThis way, you have a much cleaner route table. In general, you should always remember that whatever you can not do by the HTTP verbs should be put either in the headers or in the query parameters.
Excellent.
With JWT, you can do something called scoped authentication which means that a specific JW Token can access only a specific list of resources. Usually, you encode this in the
bodyof the token with content something like:scopes: [ 'USER:GET', 'USER:MODIFY' ]Then, in the routes, you can make sure that the required scope exists; if it doesn't, give a 403 error.
To make sure that the user can only change his/her profile, you can add:
scopes: [ 'USER:MODIFY-SELF' ]Of course, this is a very simple scheme and you can get all fancy with it but this is a good starting point.
I hope this made everything clear! If you are still stuck, drop a comment and I will be more than happy to help you! :)