0

It's a general design question about the design of RESTful routes for related/nested resources at the example of ExpressJS with MongoDB. In summary, how should I design such nested/linked routes?

About my application/scenario: I've a RESTful service implemented with NodeJS/ExpressJS and MongoDB. I've two different related models Category and Article.

const mongoose = require('mongoose');

const article = new mongoose.Schema({

    title: {

        type: String,
        required: true
    },
    body: {

        type: String,
        required: true
    },
    category: {

        type: mongoose.Types.ObjectId,
        ref: 'Category',
        required: true
    }
});

const category = new mongoose.Schema({

    name: {

        type: String,
        required: true
    }
});

I found two ways to design the relation ship respectively the routes:

Relationship oriented

This means nested paths are used and the relationship is straight forward /api/categories/:category/articles/:article.

The advantage is that's super easy to set the article's category because it's possible to preload it by the identifier path param (:category) with express middleware.

router.post('/', (request, response, next) => {

    let article = new Article(request.body);

    article.category = request.category; // Preloaded category

    ...
});

The disadvantage is that's really hard to get all articles by oen specific user because with that design you get only all articles for one category. For Example /api/categories/1/articles you get only articles for the first category so if you filter with queries for examle ?user=5 you will find only the articles of user 5 for category 1 but not all of user 5's articles.

Accessibility oriented

This means no deep nested routes and separate "endpoint's" for each resource /api/categories/:category AND /api/articles/:article.

The advantage is that's now super easy to filter by the highly diverse properties and condiftions like ?user=5 or ?title=Works.

A big disadvantage is now that I can't just use the path params identifier for a category because it doesn't exist. The means the user must specify inside of the request body the category. Are there best practices to implement this?

Which design would you prefer and are there any best practices for dealing with the disadvantage?

EDIT

I forgot the specify that I found this article but it doesn't seem to deal with the mentioned disadvantages. I'm highly interested in approachs to deal with them.

0x1C1B
  • 1,204
  • 11
  • 40
  • Take in mind that using something like /path/category/article would led you to broken links every time an article happen to change its category. – bitifet Feb 13 '19 at 14:41

1 Answers1

0

If I understand you properly, you can consider the following routes:

  • /categories: List all categories
  • /categories/:categoryId: If you decide to make the list of categories scanty, this may provide extra details about one category
  • /categories/:categoryId/users All users with the given category
  • /categories/:categoryId/users?gender=M All male users within the given category
  • /articles List all articles
  • /articles/:articleId List more details about the article ID

Have a look at Resource Naming here

The idea is - If you want more details, e.g. /categories/:categoryId and I want just users, I could define the route as categories/:categoryId?select=users

Please note that these are just recommendations to improving your code. If after exhausting all options, you cannot adhere to the stated recommendation, I advice you describe the anomaly in detail in a comment form and proceed.

cross19xx
  • 3,170
  • 1
  • 25
  • 40