No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Separación de responsabilidades con express.Router

9/27
Recursos

Aportes 57

Preguntas 19

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Ya maneje la organización de manera distinta usando clases en typescript, y dentro de las clases manejo los middlewares, routes o listen del servidor mediante métodos.

Mi estructura de directorios es algo así

el index.ts ubicado en el directorio raíz inicialice la clase y posteriormente ejecuta el método listen

import {Server} from "./app/server"

const server = new Server();
server.listen()

y el index.ts dentro de app/server/ se encuentra la clase donde se ejecuta express

import express from "express";
import products from "../routes/products";
export class Server {
  port: string | number;
  app: express.Application;
  paths: { [index: string]: string };
  constructor() {
    this.port = 8000,
    this.app = express(),
    this.paths = {
      products: "/api/products",
      users: "/api/users",
      categories: "/api/categories"
    };
    this.routes();
  }

  routes(): void {
    this.app.use(this.paths.products, products)
  }

  listen(): void {
    this.app.listen(this.port, () => {
      console.log(`Corriendo en ${this.port}`);
    });
  }
}

y para las rutas es muy similar a como lo realiza el instructor, ejemplo para products.ts

import { Router } from "express";
import faker from "faker";
const router = Router();

router.get("/", (req, res) => {
  const { size } = req.query;
  const products = [];
  const limit = size || 100;
  for (let index = 0; index < limit; index++) {
    products.push({
      name: faker.commerce.productName(),
      price: parseInt(faker.commerce.price(), 10),
      image: faker.image.imageUrl(),
    });
  }
  res.send(products);
});

router.get("/filter", (req, res) => {
  res.json({ msg: "Soy un filtro" });
});

router.get("/:id", (req, res) => {
  const { id } = req.params;
  res.send({ id, name: "product1", price: "1000" });
});

export default router;

Amigos, acá unos conceptos que le pueden aclarar dudas.

Express.Router

Crea un controlador(handler) de rutas modulares y montables. Una instancia de Router es un sistema de enrutamiento y middleware completo, por esa razón lo podemos tomar como si fuera una mini app.

Cada modulo de nuestras rutas es una mini aplicación en la que creamos sus rutas independientes y podemos incluirle middlewares, que se ejecutarán cuando se coincida con el path.

Qué es un middleware?

Un middleware es un bloque de código que se ejecuta entre la petición que hace el usuario (request) hasta que la petición llega al servidor.

Fuente:

Middlewares en Node.js

App.use

app.use Lo que hace es montar un middleware en la ruta especificada. Por ejemplo:

var express = require('express')
var router = express.Router()

// middleware específico a este router
router.use('/', function (req, res, next) {
  console.log('Hola, soy el middleware')
  next() // se utiliza para que se ejecute el router.get
})
// define the home page route
router.get('/', function (req, res) {
  res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
  res.send('About birds')
})

module.exports = router

Los tan respetados principios SOLID https://profile.es/blog/principios-solid-desarrollo-software-calidad/
me he dado cuenta que el ir entendiendolos poco a poco, nos hace ser mejores desarrolladores.

Mi solución





Esta clase me encanto, lo dejo todo muy claro y muy bien explicado, llevaba meses preguntándome como debería yo hacer esto?! y hasta que por fin!! ahora me siento como que estoy apunto de Graduarme! jajaja

solución

const productsRouter = require('./productsRouter');
const usersRouter = require('./usersRouter');
const categoriesRouter = require('./categoriesRouter');

function routerApi(app) {
  app.use('/api/products', productsRouter);
  app.use('/api/users', usersRouter);
  app.use('/api/categories', categoriesRouter);
}

module.exports = routerApi;

así me quedó utilizando typescript

Mi aporte, de mis clases preferidas de este curso

TIP para quién lo esté haciendo con module y no common. (usando IMPORTS xxx from “./algo”) y no los "const data = require(‘algo’)"
El final del path debe terminar en .js y los archivos “index” también deben ser escritos y finalizados en .js => import routerApi from “./routes/index.js” de lo contrario crashea.

Mi solución

Que buenas recomendaciones sobre las formas de organizar el proyecto!

Single responsability principle

El principio de responsabilidad única o SRP en ingeniería de software establece que cada módulo o clase debe tener responsabilidad sobre una sola parte de la funcionalidad
.
para nuestro proyecto separaremos las responsabilidades por cada entidad, crearemos una nueva carpeta routes en la raíz con archivos entidad.router.js por cada entidad
.
estos archivos tendrán su propio router por entidad con todas sus rutas correspondientes y serán exportados cada uno como modulo, la idea es crear un enrutador aparte por cada entidad y después inyectarlo a la aplicación

routes/product.router.js:

const express = require('express')
const { faker } = require('@faker-js/faker')

const router = express.Router()

router.get('/', (req,res)=> {
    const { limit = 10 } = req.query
    const products = []

    for (let i = 0; i < limit; i++){
        products.push({
            name: faker.commerce.productName(),
            price: faker.commerce.price(),
            image: faker.image.imageUrl()
        })
    }

    res.json(products)
})

router.get('/:id', (req,res)=> {
    const { id } = req.params
    res.json({
        id,
    })
})

module.exports = router

routes/categories.router.js:

const express = require('express')
const { faker } = require('@faker-js/faker')

const router = express.Router()

router.get('/', (req,res)=> {
    const { limit = 10 } = req.query
    const categories = []

    for (let i = 0; i < limit; i++){
        categories.push({
            name: faker.random.word()
        })
    }

    res.json(categories)
})

router.get('/:id', (req,res)=> {
    const { id } = req.params
    res.json({
        id,
    })
})

module.exports = router

routes/users.router.js:

const express = require('express')
const { faker } = require('@faker-js/faker')

const router = express.Router()

router.get('/', (req,res)=> {
    const { limit = 10 } = req.query
    const users = []

    for (let i = 0; i < limit; i++){
        users.push({
            firstName: faker.name.firstName(),
            lastName: faker.name.lastName(),
            gender: faker.name.gender(),
            jobTitle: faker.name.jobTitle(),
        })
    }

    res.json(users)
})

router.get('/:id', (req,res)=> {
    const { id } = req.params
    res.json({
        id,
    })
})

module.exports = router

luego creamos un archivo principal con nombre index.js dentro de la carpeta routes, que importa el router de cada una de las entidades y contiene una función routerApi que recibe como parámetro el server o aplicación y hace uso del router importado de una entidad u otra dependiendo el inicio de la url visitada y será exportada como un modulo
routes/index.js:

const products = require('./products.router')
const categories = require('./categories.router')
const users = require('./users.router')

const routerApi = (app) => {
    app.use('/api/products', products)
    app.use('/api/categories', categories)
    app.use('/api/users', users)
}

module.exports = routerApi

como ultimo paso, en nuestro index.js que se encuentra en la raíz del proyecto, debemos importar esta función routerApi anteriormente creada, ejecutarla y pasarle por parámetro el server o aplicación inicializada con Express que se encuentra escuchando en el puerto seleccionado
index.js:

const express = require('express')
const app = express()

const routerApi = require('./routes')
routerApi(app)

const port = 3000
app.listen(port, ()=> {
    console.log(`Listening on port${port}`)
})

si visitamos la url "/api/products" veremos como respuesta de parte del servidor un arreglo con 10 productos

[
  {
    "name": "Fantastic Plastic Chicken",
    "price": "874.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Oriental Bronze Mouse",
    "price": "956.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Licensed Frozen Gloves",
    "price": "783.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Small Frozen Bike",
    "price": "901.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Licensed Metal Pants",
    "price": "905.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Elegant Rubber Chicken",
    "price": "201.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Ergonomic Concrete Sausages",
    "price": "385.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Recycled Metal Fish",
    "price": "206.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Ergonomic Concrete Pizza",
    "price": "719.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Ergonomic Fresh Sausages",
    "price": "960.00",
    "image": "https://loremflickr.com/640/480"
  }
]

si visitamos la url "/api/products?limit=3" veremos como respuesta de parte del servidor un arreglo con 3 productos

[
  {
    "name": "Awesome Soft Table",
    "price": "341.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Luxurious Cotton Gloves",
    "price": "628.00",
    "image": "https://loremflickr.com/640/480"
  },
  {
    "name": "Electronic Frozen Keyboard",
    "price": "615.00",
    "image": "https://loremflickr.com/640/480"
  }
]

si visitamos la url "/api/products/1" veremos como respuesta de parte del servidor en JSON con el numero de id pasado

{
  "id": "1"
}

si visitamos la url “/api/categories” veremos como respuesta de parte del servidor un arreglo con 10 categorías

[
  {
    "name": "payment"
  },
  {
    "name": "Indium"
  },
  {
    "name": "Diesel"
  },
  {
    "name": "Porsche"
  },
  {
    "name": "hmph"
  },
  {
    "name": "Dong"
  },
  {
    "name": "Borders"
  },
  {
    "name": "Fish"
  },
  {
    "name": "communities"
  },
  {
    "name": "cyan"
  }
]

si visitamos la url "/api/categories?limit=3" veremos como respuesta de parte del servidor un arreglo con 3 categorías

[
  {
    "name": "City"
  },
  {
    "name": "Pickup"
  },
  {
    "name": "Elyse"
  }
]

si visitamos la url "/api/categories/1" veremos como respuesta de parte del servidor en JSON con el numero de id pasado

{
  "id": "1"
}

si visitamos la url "/api/users" veremos como respuesta de parte del servidor un arreglo con 10 usuarios

[
  {
    "firstName": "Claudie",
    "lastName": "Walsh",
    "gender": "Gender nonconforming",
    "jobTitle": "Investor Assurance Planner"
  },
  {
    "firstName": "Parker",
    "lastName": "Hills",
    "gender": "Transexual female",
    "jobTitle": "Customer Functionality Planner"
  },
  {
    "firstName": "Halie",
    "lastName": "Kulas",
    "gender": "Demi-woman",
    "jobTitle": "Product Applications Facilitator"
  },
  {
    "firstName": "Lonie",
    "lastName": "Ernser",
    "gender": "Female to male transsexual man",
    "jobTitle": "Corporate Factors Planner"
  },
  {
    "firstName": "Johanna",
    "lastName": "Johns",
    "gender": "Intersex woman",
    "jobTitle": "International Tactics Officer"
  },
  {
    "firstName": "Henriette",
    "lastName": "Hackett",
    "gender": "Transexual person",
    "jobTitle": "Global Response Liaison"
  },
  {
    "firstName": "Marianne",
    "lastName": "Bernier",
    "gender": "Demi-boy",
    "jobTitle": "Chief Usability Officer"
  },
  {
    "firstName": "Rex",
    "lastName": "Koss",
    "gender": "Cis",
    "jobTitle": "Direct Mobility Planner"
  },
  {
    "firstName": "Norbert",
    "lastName": "Conn",
    "gender": "Cisgender female",
    "jobTitle": "Product Operations Agent"
  },
  {
    "firstName": "Nikko",
    "lastName": "Ruecker",
    "gender": "Cis",
    "jobTitle": "Product Brand Producer"
  }
]

si visitamos la url "/api/users?limit=3" veremos como respuesta de parte del servidor un arreglo con 3 usuarios

[
  {
    "firstName": "Dayne",
    "lastName": "Moore",
    "gender": "Xenogender",
    "jobTitle": "Principal Data Producer"
  },
  {
    "firstName": "Sterling",
    "lastName": "Hane",
    "gender": "T* woman",
    "jobTitle": "Future Quality Specialist"
  },
  {
    "firstName": "Liza",
    "lastName": "Mann",
    "gender": "Woman",
    "jobTitle": "Direct Functionality Administrator"
  }
]

si visitamos la url "/api/users/1" veremos como respuesta de parte del servidor en JSON con el numero de id pasado

{
  "id": "1"
}

de esta forma estaríamos modularizando la aplicación, y conectando todo de tal forma que cada entidad tenga su propio router con sus propias rutas y sea responsable de gestionar solo lo correspondiente a esa entidad, sea los productos, categorías, usuarios etc.

Mi solución al momento

  • index.js
  • routes/index
  • db/init.db
  • routes/products.router

Les comparto que agregue las rutas usuarios y categorías:

Categorias

const express = require('express');
const faker = require('faker');

const router = express.Router();

router.get('/',(req,res) => {
  const {size} = req.query;
  const limit = size || 10;
  const categories = [];
  for(let i = 0; i < limit; i++){
    categories.push({
      category:faker.commerce.productAdjective()
    })
  }
  res.json(categories);
});

router.get('/:id', (req,res) => {
  const {id} = req.params;
  res.json({
    id,
    category:faker.commerce.productAdjective()
  })
})

module.exports = router;

Usuarios

const express = require('express');
const faker = require('faker');

const router = express.Router();

router.get('/', (req,res) =>{
  const {size} = req.query;
  const limit = size || 10;
  const users = [];
  for(let i = 0; i < limit; i++){
    users.push({
      user:faker.internet.userName()
    })
  }
  res.json(users);
});

router.get('/:id', (req,res) => {
  const {id} = req.params;
  res.json({
    id,
    user:faker.internet.userName(),
  })
});

module.exports = router;

Desde faker es posible generar usuarios, es muy interesante lo que se puede generar con éste módulo, les comparto el link de donde pueden obtener más información: faker npm

En Django lo llamamos application_name/urls.py

https://expressjs.com/es/guide/routing.html les recomiendo que lean la siguiente lectura para profundizar

en este video se puede ver otra forma para esto, aplicando una arquitectura por capas https://platzi.com/clases/1689-nodejs-mongo-websockets/22632-conceptualmente-rutas-controladores-y-bases-de-dat/

Porqué mi código marca un typeerror: cannot read properties of undefined (reading 'use') en: app.use('/products', productsRouter) `const productsRouter = require('./products');` `const routerApi = (app) => {  app.use('/products', productsRouter);` `module.exports = routerApi;`
No me funcionó, al final explicó muy rápido y trato de ejecutar pero no funciona el localhost

MI SOLUCIÓN

Cree una variable de entorno

instalé dotenv npm i dotenv

En el archivo index.js del router puse el siguiente código y listo, ojo agregué v1 después de api

puedes inicializar directamente la funcion para luego solo extender su funcionamiento

const router = require('./router/')(app);

Tuve problemas con la librería Faker y la reemplace por Change

npm install chance
const express = require('express');
const router = express.Router();
const Chance = require('chance');

router.get('/', (req, res) => {
  res.json(getUsers());
});

function getUsers(count = 10) {
  let users = [];
  let chance = new Chance();
  for (let index = 1; index <= count; index++) {
    const user = {
      id: index,
      name: chance.name({ nationality: 'it' }),
      email: chance.email(),
      image: chance.avatar(),
    };
    users.push(user);
  }
  return users;
}

module.exports = router;

SINGLE RESPONSABILITY PRINCIPLE

El principio de responsabilidad única o SRP en ingeniería de software establece que cada módulo o clase debe tener responsabilidad sobre una sola parte de la funcionalidad proporcionada por el software y esta responsabilidad debe estar encapsulada en su totalidad por la clase

Me aporte sin duda la mejor clase del Mes

Nunca había entendido esto, ahora siento que todo se ajusta mejor.

Ahora ya tengo todo en módulos!!

Decepcionante esta clase!
el profe nos puso en el .editorconfig una config que me hizo rabiar un poco, si les molesta que aveces les haga como un salto de línea automático tienen que modificar: `insert_final_newline = true` y setearlo en false.
![](https://static.platzi.com/media/user_upload/image-78fe6c72-bdf4-4fcc-b095-567a2d3fe68b.jpg)![](https://static.platzi.com/media/user_upload/image-92a3b2a1-de0a-4626-ae23-ce51c2d98f5a.jpg)
como puedo tener ayuda con los videos que se traban? llevo 1 hora viendo este video... y no es la red, ya revise y tengo las 500mb funcionando sin problema y aun asi se bloquea el video, se congela cada 5 o 10 seg

Basta con agregarlo en el index de routes:

Tambien se puede considerar agregar una carpeta adicional dentro de /routes para versionar las api algo como:

/routes
 |__v1
	|__ products.js
	|__ categories.js
tengo un modulo de vehiculos, personal y productos

Para las personas en 2023 teniendo problemas con faker.js, estoy revisando que existe una libreria que surge como alternativa --> falso.js https://ngneat.github.io/falso/docs/commerce

Esta es la solucion que encontré para no ir añadiendo cada vez /api/ dentro del index de routes, de esta forma solo tiene un sitio donde poder cambiarlo:

const express = require('express');
const routerApi = require('./routes')

const app = express();
const port = 3005;
//el cambio viene aqui: 
const apiRouter = express.Router();
app.use('/api',apiRouter);

app.listen(port, () => {
    console.log('Estamos corriendo en el puerto:', port);
});

apiRouter.get("/", (req, res) => {
    res.send('Hola, estamos up!');
});

apiRouter.get('/nueva-ruta', (req, res) => {
    res.send('Esta es una nueva ruta!!');
});

routerApi(apiRouter);

Lo que hago es crear una ruta “Padre”, a partir de aqui cualquier nueva ruta que cree ya tendrá el “/api” por defecto.

mi solucion para separar responsabilidades:

const { TOKENS, APIS } = require('../TOKENS');
const logger = require('../utils/logger');
const productsRouter = require('./router.products');
const categoriesRouter = require('./router.categories');
const userRouter = require('./router.user');

function routerApi (app) {
  app.use(APIS.apiV1(TOKENS.KEYS.USERS), userRouter)
  app.use(APIS.apiV1(TOKENS.KEYS.CATEGORIES), categoriesRouter)
  app.use(APIS.apiV1(TOKENS.KEYS.PRODUCTS), productsRouter)
};

module.exports = routerApi;

const logger = require("./utils/logger");

const TOKENS = {
  KEYS: {
    USERS: 'USERS',
    PRODUCTS: 'PRODUCTS',
    CATEGORIES: 'CATEGORIES'
  },
  ROUTES: {
    USERS: 'users',
    PRODUCTS: 'products',
    CATEGORIES: 'categories',
  },
};

const APIS = {
  apiV1: function(token) {
    logger.debug('APIV1', token)
    return `/api_v1/${TOKENS.KEYS[ token ]}`
  }
}

module.exports = {
  TOKENS,
  APIS
}
Esta clase me confundió un poco. Entendí lo que se hacía pero necesito algo más gráfico para entenderlo por completo, hubiera estado genial que usaran algo más gráfico

Good class!! thanks teacher!

Implemente TS para todo

cree un nodemon.json

{
  "watch": ["app"],
  "ext": "ts",
  "exec": "ts-node app/index.ts"
}

tsconfig.json

{
  "include": ["**/*"],
    "compilerOptions": {
      "target": "es2016",
      "module": "commonjs",
      "moduleResolution": "node",
      "sourceMap": true,
       "outDir": "./dist",
      "esModuleInterop": true,
      "forceConsistentCasingInFileNames": true,
      "strict": true,
      "skipLibCheck": true
    }
  }

y en package.json

"scripts": {
    "build": "npx tsc",
    "start": "node dist/index.js",
    "dev": "nodemon"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/express": "^4.17.17",
    "@types/faker": "^6.6.9",
    "@types/node": "18.14.6",
    "concurrently": "7.6.0",
    "eslint": "^7.32.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^3.4.1",
    "nodemon": "2.0.21",
    "prettier": "^2.3.2",
    "ts-node": "10.9.1",
    "typescript": "4.9.5"
  },
  "dependencies": {
    "dotenv": "16.0.3",
    "express": "4.18.2",
    "faker": "^5.5.3"
  }

en mi archivo index.ts principal

import dotenv from "dotenv";
import { Server } from "./server";

dotenv.config();
Server();

archivo server.ts

import express, { Application } from "express";
import productsRouter from "../products/routes/products";
export const Server = () => {
  const app: Application = express();
  const port: string = process.env.PORT || "";
  const host: string = process.env.URL || "";
  const path: { products: string; auth: string } = {
    products: "/api/products",
    auth: "api/auth",
  };
  const router = () => {
    app.use(path.products, productsRouter);
  };

  const listen = () => {
    try {
      router();
      app.listen(port, () => {
        console.log(`Run app in ${host}:${port}`);
      });
    } catch (error) {
      console.log("Error:", error);
    }
  };
  listen();
};

router.ts

import { filter, getProducts, getProductsById } from "../controller/products";
import { Router } from "express";

const router: Router = Router();

router.get("/", getProducts);
router.get("/filter", filter);
router.get("/:id", getProductsById);

export default router;

products.ts controller

import { Request, Response } from "express";
import { getProductsProps } from "./types";
const faker = require("faker");

let products: getProductsProps[] = [];

export const getProducts = (req: Request, res: Response) => {
  products = [];
  const { size } = req.query;
  const limit = size || 10;
  for (let index = 0; index < limit; index++) {
    products.push({
      id: index,
      name: faker.commerce.productName(),
      price: parseInt(faker.commerce.price(), 10),
      image: faker.image.imageUrl(),
    });
  }
  res.json(products);
};

export const getProductsById = (req: Request, res: Response) => {
  const { id } = req.params;
  for (let index = 0; index < 10; index++) {
    products.push({
      id: index,
      name: faker.commerce.productName(),
      price: parseInt(faker.commerce.price(), 10),
      image: faker.image.imageUrl(),
    });
  }
  const filterById = products.find((item) => item.id === parseInt(id));
  res.json(filterById);
};
export const filter = (req: Request, res: Response) => {
  res.send("Yo soy un filter");
};

Los demás archivos son como el que vimos en la clase, pero el index.js de routes lo hice así:

const productsRouter = require('./products.router');
const usersRouter = require('./users.router');
const categoriesRouter = require('./categories.router');

const routerApi = (app) => {
  app.use('/api/products', productsRouter);
  app.use('/api/users', usersRouter);
  app.use('/api/categories', categoriesRouter);
}

module.exports = routerApi;

En commonjs no es necesario colocarlee la extención al archivo importado?

muy god este profe

profe por que no se puede usar es6 para importar o en general?

Mi solución al reto:

const parentRoute = '/api'

function routersApi(app) {
  app.use(parentRoute + '/products', productsRouter);
  app.use(parentRoute + '/users', usersRouter);
  app.use(parentRoute + '/categories', categoriesRouter);
  app.use(parentRoute + '/services', servicesRouter);
};

Hice toda la refactorización del routing sin problemas y añadí el tag de /api/ entre las rutas:

const productsRouter = require('./products.router');
const usersRouter = require('./users.router');
const categoriessRouter = require('./categories.router');

function routerApi(app) {
  app.use('/api/products', productsRouter);
  app.use('/api/users', usersRouter);
  app.use('/api/categories', categoriessRouter);
}

module.exports = routerApi;

Este profesor es genial!

crear rutas con index, crear modulos, ordenar las rutas express y dos clases desés de fakeer

Que buen profesor! explica muy bien y comenta cosas importantes
const productsRouter = require('./products.router');
const categoriesRouter = require('./categories.router');
const usersRouter = require('./users.router');

const prefixApi = '/api';

function routerApi(app) {
  app.use(`${prefixApi}/products`, productsRouter);
  app.use(`${prefixApi}/categories`, categoriesRouter);
  app.use(`${prefixApi}/users`, usersRouter);
}

module.exports = routerApi;

Este curso esta excelente, todo me esta quedando muy claro, de los mejores profes de platzi .

Excelente método para separar las responsabilidades y hacer nuestro código más legible y adaptable a cambios.
Esta fue mi solución:

Solo que me ocurre poner así

const productsRouter = require('./products.router');
const categoriesRouter = require('./categories.router');
const usersRouter = require('./users.router');
const ordersRouter = require('./orders.router');

function routerApi(app) {
  app.use('/api/products', productsRouter);
  app.use('/api/categories', categoriesRouter);
  app.use('/api/users', usersRouter);
  app.use('/api/orders', ordersRouter);
}

module.exports = routerApi;

Totalmente recomendado leer la documentacion oficial para entender mejor al profe. Lo que hemos visto hasta ahora aqui https://expressjs.com/en/guide/routing.html

Me gusta mucho esta clase que muestre de una manera simple como utilizar los principios SOLID en node

esta clase fue geniallllllllllll ¡¡¡

responsabilidades *

Mi solución al reto fue, además de exportar el router de cada archivo, exportar el nombre de la ruta, además de agregar un parámetro a la funcion routerApi(), de este modo, se puede cambiar el prefijo sin tener que realizar todas las modificaciones, y se agregará a las rutas, sin tener que hacerlo manualmente.

const products_router = require('./products');
const users_router = require('./users');
function routerApi(app, prefix = "api") {
    const routers = [products_router, users_router];

    routers.forEach((element) => {
        app.use(`/${prefix}/${element.route_name}`, element.router)
    })
}
module.exports = routerApi;

en los routers individuales, la exportacion:

module.exports = { route_name: 'products', router: products_router };

y a la hora de aplicar el router, donde podemos variar facilmente el parametro

routerApi(app, "api");