Reputation: 71
I have a Rest API where a user can create a list and then put list items in it (for a quiz). My schema structure is this:
const verbListSchema = {
title: String,
verbs: [{verb: String}]
};
Here are the url endpoints I have so far:
/lists/ (gets back all the lists)
/lists/verbs (gets all the verbs from all the lists)
My question is - I want to get, post, patch and delete a specific list using its id, like /lists?list_id=123/verbs
or /lists/123/verbs
and then one step further to get individual verbs I want to do something like /lists/123/verbs/124
or /lists?list_id=123/verbs?verb_id=124
the last doesn't work because it counts the last endpoint as a query param.
In terms of best practice what's the best way to do this. I could do something like this (I use express.js)?
app.[request-type]("/lists") {...}
app.[request-type]("/lists/:list_id") {...}
app.[request-type]("/lists/:list_id/verbs") {...}
app.[request-type]("/lists/:list_id/verbs/:verb_id") {...}
and then if I want to retrieve all the lists, not just a specific one I can check if the list_id is "all" like, /lists/all/verbs
?
And here is my code so far:
const express = require("express");
const verbRouter = require("./verbRoutes");
const router = express.Router();
const VerbList = require("../../verb-list-db");
const isOriginal = async (req,res,next) => {
const listExists = await VerbList.find({title: req.body.listTitle})
if (listExists.length > 0 ) return res.status(400).json({message: "list already exists"});
next();
};
router.route("/")
.get(async (req,res,next) => {
try {
const listId = req.query.list_id;
if (listId) return res.json(await VerbList.find({_id: listId}));
const lists = await VerbList.find({});
res.json(lists);
} catch(err) {next(err)}
})
.post(isOriginal, async (req,res,next) => {
const newList = new VerbList({ // creates a new list
title: req.body.listTitle
})
newList.save()
.then(() => {return res.send("list successfully added!")})
.catch(err => next(err));
})
.patch(isOriginal, async (req,res,next) => {
try {
const listId = req.query.list_id;
if (!listId) throw new Error("you must have a list_id to patch!")
res.json(await VerbList.updateOne({_id: req.query.list_id}, {title: req.body.listTitle}))
} catch(err) {next(err)}
})
.delete(async (req,res,next) => {
try {
const listId = req.query.list_id;
if (!listId) throw new Error("you must have a list_id to delete!");
res.json(await VerbList.deleteOne({_id: req.query.list_id}))
} catch(err) {next(err)}
})
Any suggestions would be appreciated :)
Upvotes: 0
Views: 63
Reputation: 52
You can try to modularize your express code by separating your /lists
routes from your main server.js (or index.js) file.
index.js
const express = require('express');
const app = express();
//Now lets route all the API requests that start with '/list' to a file called lists.js
app.use('/lists', require('/path/to/lists.js')
app.listen(3000, () => console.log(`\nServer started on port 3000`))
lists.js
const express = require('express');
const router = express.Router();
// now you know all the requests in this file would be for /list so lets implement a router for fetching all the lists
router.get('/', async(req, res) => {
*** add all your logic for /lists endpoints here**
res.status(200).json(lists_json_response); //send a response back to your client
})
//you can create as many endpoints as you want in this file for endpoints that start with '/lists'
router.[request-method]("/lists/:list_id") {...} // endpoint for requesting a specific list
router.[request-method]("/:list_id/verbs") {...} //endpoint for requesting all the verbs for a specific list
router.[request-method]("/lists/all/verbs") {...} // all the verbs in all the lists
module.exports = router;
Also you cant put query parameters in the middle of an endpoint. if it is going to be a variable that you need and its not in the end of the URL, you have to pass it as a param, e.g.:
instead of doing /lists?list_id=123/verbs?verb_id=124
, you can do something like /lists/123/verbs/124
to look for the verb with id 124 in a list with id 123.
so to listen to a request to this endpoint, you can design another endpoint in your lists.js file like this:
router[request-method].('/:list_id/verb/:verb_id', async(req, res)=> {
var list_id = req.params.list_id
var verb_id = req.params.verb_id
***
now use the list_id and verb_id to query the requested data and send a response back to the client
***
})
Upvotes: 1