jake_prentice
jake_prentice

Reputation: 71

Express Rest Api: question about routing?

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

Answers (1)

Sina
Sina

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

Related Questions