I am working on a project using relational mysql DB. My tables are:
Using Node/Express
Simplified code structure:
/routers
/routers/User.js
/routers/Location.js
/routers/Crop.js
/controlers
/controlers/UserController.js
/controlers/LocationController.js
/controlers/CropController.js
/models
/models/UserModel.js
/models/LocationModel.js
/models/CropModel.js
app.js
The relation is that user can have many locations (farms) and on a location there may be many crops planted.
The DB relation stuff is done , no problem with that. My question is about how to logically structure my code and in the same time keep the REST principle in tact!
I am wondering from API point of view about the endpoint urls.
Currently they are:
hostname/api/user/:id - user account
hostname/api/user/:id/locations - user locations
hostname/api/user/:id/locations/:locationid - information about specific location belonging to specific user
hostname/api/user/:id/locations/:locationid/crops - list all crops which are planted on specific location , which belong to specific user
Is this url structure OK from rest perspective?
And after request is received in the API i cant wrap my head arround ... which router and controller should be responsible for my routes, ex:
hostname/api/user/:id/locations/:locationid
Should this url be handled from user router and controller? Or from locations router and controller?
The url clearly says: "For user with :id, find me location with :locationid which belongs to him.". So, me as unexperienced developer automatically assume that this route should be inside User router:
UserRouter.get(/:id/locations/:locationid, function(....){
UserController.getUserLocationById(:id, :locationid);
})
app.use('/user', UserRouter)
But this way, i think i will en up with User router containing all possible urls:
/user
/user/:id
/user/:id/locations
...
...
/user/:id/crops
/user/:id/crops/:cropid
...
And nothing in other routers and controllers. And i this fact only is making me think that i am thinking wrong about REST API code structure.
Currently every route that starts with /user.... is handled by my User Express router and then passed to UserController.getUserLocationById in the above example url.
But i think i make a mistake this way.
If someone understood my headbanging , can you please help me solve that out?
Best Regards
Your routing looks clear to me and conforms to REST. Reading the pseudo urls, to me it results comprehensible what result you are going to get using them.
My opinion about the actual implementation is that each router should be responsible to handle the route based on the first token (user, location, crop...), and the inner mapping to the responsible Controller should be done based on the data you are about to return.
To me you can follow this:
URL: hostname/api/user/:id
ROUTE: user
DATA: user
URL: hostname/api/user/:id/locations
ROUTE: user
DATA: location
URL: hostname/api/user/:id/locations/:locationid
ROUTE: user
DATA: location
URL: hostname/api/user/:id/locations/:locationid/crops
ROUTE: user
DATA: crop
URL: hostname/api/locations/:locationid
ROUTE: location
DATA: location
URL: hostname/api/locations/:locationid/crops
ROUTE: location
DATA: crop
URL: hostname/api/crops/:cropid/locations
ROUTE: crop
DATA: location
Route, will be the Router responsible to handler the incoming request. Data, will be the Controller responsible to provide the data, do validation and so on.
Doing so each controller will be responsible only to serve the data it is the owner for, no matter which url you use to get there. Of course, the routing (URL) will be fundamental to understand which filter to apply and therefore which subset of data to return.