Node / Express Guide

Routes

Route file conventions, router factory pattern, and REST method conventions.

Routes wire HTTP paths to controller functions and compose middleware. Each resource has its own route file.

Pattern

Route files export a factory function that returns an Express Router:

// src/routes/auth.route.ts
import { Router } from 'express'
import { useAuthController }      from '../controllers/auth.controller'
import { useRevokedTokenRepo }    from '../repositories/revoked-token.repo'
import { authenticate }           from '@codisolutions23/node-utils'
import { resolveOptionalTenant }  from '../middleware/tenant.middleware'
import { accessTokenSecret }      from '../config'

export default function useAuthRoute() {
  const router = Router()
  const { existsByJti }                    = useRevokedTokenRepo()
  const { login, refreshToken, logout, getCurrentUser } = useAuthController()

  // Build middleware instances once per router
  const authMiddleware = authenticate(accessTokenSecret, existsByJti)

  router.post('/login',    resolveOptionalTenant, login)
  router.post('/refresh',  refreshToken)
  router.get('/user',      authMiddleware, getCurrentUser)
  router.delete('/logout', authMiddleware, logout)

  return router
}

Route Index

All routes are mounted in src/routes/index.ts under /api/:

// src/routes/index.ts
import { Router } from 'express'
import useAuthRoute     from './auth.route'
import useUserRoute     from './user.route'
import useResourceRoute from './resource.route'

const router = Router()

router.use('/auth',      useAuthRoute())
router.use('/users',     useUserRoute())
router.use('/resources', useResourceRoute())

export default router

Mounted in src/app.ts:

app.use('/api', routes)

Middleware Composition

Middleware is composed per route — not globally applied unless it truly applies to all routes:

// src/routes/resource.route.ts
export default function useResourceRoute() {
  const router = Router()
  const { existsByJti }                      = useRevokedTokenRepo()
  const { getAll, create, update, remove }   = useResourceController()

  const authMiddleware          = authenticate(accessTokenSecret, existsByJti)
  const branchManagerMiddleware = requireBranchManagerOrAbove(accessTokenSecret, existsByJti)
  const adminMiddleware         = requireAdmin(accessTokenSecret, existsByJti)

  router.get('/',    authMiddleware,           getAll)
  router.post('/',   branchManagerMiddleware,  create)
  router.patch('/:id', branchManagerMiddleware, update)
  router.delete('/:id', adminMiddleware,        remove)

  return router
}

REST Conventions

OperationMethodPath
ListGET/resources
Get oneGET/resources/:id
CreatePOST/resources
Full replacePUT/resources/:id
Partial updatePATCH/resources/:id
Soft deleteDELETE/resources/:id
Sub-resource actionPATCH/resources/:id/action
Nested resourcePOST/resources/:id/related