Express Rest Api: вопрос о маршрутизации?

У меня есть Rest API, где пользователь может создать список, а затем поместить в него элементы списка (для викторины). Моя структура схемы такова:

const verbListSchema = {
    title: String,
    verbs: [{verb: String}]
};

Вот конечные точки URL, которые у меня есть до сих пор:

/lists/ (gets back all the lists)
/lists/verbs (gets all the verbs from all the lists)

Мой вопрос: я хочу получить, опубликовать, исправить и удалить определенный список, используя его идентификатор, например /lists?list_id=123/verbs или /lists/123/verbs, а затем еще один шаг, чтобы получить отдельные глаголы. Я хочу сделать что-то вроде /lists/123/verbs/124 или /lists?list_id=123/verbs?verb_id=124, последнее не работает, потому что он считает последнюю конечную точку параметром запроса.

С точки зрения передовой практики, как лучше всего это сделать. Я мог бы сделать что-то подобное (я использую 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") {...}

а затем, если я хочу получить все списки, а не только конкретный, я могу проверить, соответствует ли list_id /lists/all/verbs?

И вот мой код до сих пор:

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)}
    })

Мы ценим любые предложения :)


person jake_prentice    schedule 22.10.2020    source источник
comment
Почему бы вам не использовать один и тот же маршрут с двумя параметрами запроса? Что-то вроде: /lists/verbs?list_id=123&verb_id=124   -  person Eduardo Conte    schedule 22.10.2020
comment
что так похоже на /lists/verbs?list_id=123&verb_id=124 да, это сработает, но мне кажется, что list_id не должен быть связан с конечной точкой /lists, если вы понимаете, что я имею в виду?   -  person jake_prentice    schedule 23.10.2020


Ответы (1)


Вы можете попытаться сделать свой экспресс-код модульным, отделив маршруты /lists от основного файла server.js (или index.js).

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`))

списки.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;

Также вы не можете помещать параметры запроса в середину конечной точки. если это будет переменная, которая вам нужна, а не в конце URL-адреса, вы должны передать ее как параметр, например:

вместо /lists?list_id=123/verbs?verb_id=124 вы можете сделать что-то вроде /lists/123/verbs/124, чтобы найти глагол с идентификатором 124 в списке с идентификатором 123. Таким образом, чтобы прослушать запрос к этой конечной точке, вы можете создать другую конечную точку в своем файле lists.js следующим образом:

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
  ***
})
person Sina    schedule 10.04.2021