Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/juanjh1/asimilation/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Route modules allow you to organize related routes under a common namespace. This is essential for building large applications with many routes, as it helps maintain a clean structure and prevents route clutter.

What is a Route Module?

A route module is an object that groups related routes under a namespace prefix. All routes added to the module automatically inherit the module’s path prefix.
class RouteModule {
  addPath(path: string, callback: Controller, kwargs?: PathKwargs): void;
  createRouteModule(name: string): RouteModule;
}
Defined in core/router-manager.ts:154-172.

Creating Route Modules

Create a route module using createRouteModule() on the URL manager:
import { url } from "@asimilation/core";

// Create a module for API routes
const apiModule = url.createRouteModule("/api");

// All routes in this module start with /api
apiModule.addPath("/users", (req, res) => {
  res.sendJson({ users: [] }, 200);
}); // Registered as /api/users

apiModule.addPath("/posts", (req, res) => {
  res.sendJson({ posts: [] }, 200);
}); // Registered as /api/posts
The namespace path is automatically normalized, so leading slashes are optional (see router-manager.ts:161).

Nested Modules

Route modules can be nested to create deeper hierarchies:
import { url } from "@asimilation/core";

// Create API module
const apiModule = url.createRouteModule("/api");

// Create v1 sub-module
const v1Module = apiModule.createRouteModule("/v1");

// Add routes to v1
v1Module.addPath("/users", (req, res) => {
  res.sendJson({ version: "v1", users: [] }, 200);
}); // Registered as /api/v1/users

// Create v2 sub-module
const v2Module = apiModule.createRouteModule("/v2");

v2Module.addPath("/users", (req, res) => {
  res.sendJson({ version: "v2", users: [] }, 200);
}); // Registered as /api/v2/users

Path Normalization

Paths are automatically normalized when creating modules (see helpers/url-regex.ts:38-47):
// These all create the same module:
url.createRouteModule("api");      // Normalized to /api
url.createRouteModule("/api");     // Already normalized
url.createRouteModule("//api//");  // Normalized to /api

// The namespace is combined with route paths:
apiModule.addPath("users");    // /api/users
apiModule.addPath("/users");   // /api/users
apiModule.addPath("//users//"); // /api/users
Don’t worry about leading or trailing slashes - Asimilation handles them automatically.

Complete Example: RESTful API

Here’s how to organize a complete RESTful API using route modules:
import { url } from "@asimilation/core";

// Create main API module
const apiModule = url.createRouteModule("/api");

// Users module
const usersModule = apiModule.createRouteModule("/users");

// List users - GET /api/users
usersModule.addPath("/", (req, res) => {
  res.sendJson({ users: [] }, 200);
}, { methods: ["GET"] });

// Get user - GET /api/users/:id
usersModule.addPath("/<int:id>", (req, res) => {
  const userId = req.params.id;
  res.sendJson({ id: userId, name: "John" }, 200);
}, { methods: ["GET"] });

// Create user - POST /api/users
usersModule.addPath("/", (req, res) => {
  res.sendJson({ created: true }, 201);
}, { methods: ["POST"] });

// Update user - PUT /api/users/:id
usersModule.addPath("/<int:id>", (req, res) => {
  const userId = req.params.id;
  res.sendJson({ updated: true, id: userId }, 200);
}, { methods: ["PUT"] });

// Delete user - DELETE /api/users/:id
usersModule.addPath("/<int:id>", (req, res) => {
  const userId = req.params.id;
  res.sendJson({ deleted: true, id: userId }, 200);
}, { methods: ["DELETE"] });

// Posts module
const postsModule = apiModule.createRouteModule("/posts");

// List posts - GET /api/posts
postsModule.addPath("/", (req, res) => {
  res.sendJson({ posts: [] }, 200);
}, { methods: ["GET"] });

// Get post - GET /api/posts/:slug
postsModule.addPath("/<slug:slug>", (req, res) => {
  const slug = req.params.slug;
  res.sendJson({ slug, title: "Post Title" }, 200);
}, { methods: ["GET"] });

Module Organization Patterns

By Feature

Organize modules around features or resources:
const apiModule = url.createRouteModule("/api");

const usersModule = apiModule.createRouteModule("/users");
const postsModule = apiModule.createRouteModule("/posts");
const commentsModule = apiModule.createRouteModule("/comments");
const authModule = apiModule.createRouteModule("/auth");

By Version

Version your API routes:
const apiModule = url.createRouteModule("/api");

const v1 = apiModule.createRouteModule("/v1");
const v2 = apiModule.createRouteModule("/v2");

// v1 endpoints
v1.addPath("/users", handlerV1);

// v2 endpoints with new features
v2.addPath("/users", handlerV2);

By Domain

Separate public and admin areas:
// Public API
const publicModule = url.createRouteModule("/api/public");
publicModule.addPath("/posts", getPublicPosts);

// Admin API
const adminModule = url.createRouteModule("/api/admin");
adminModule.addPath("/users", getAllUsers, {
  handlers: [requireAdmin]
});

File Organization

Organize your code by splitting modules into separate files:

routes/users.ts

import { RouteModule } from "@asimilation/core";

export function setupUserRoutes(parent: RouteModule) {
  const users = parent.createRouteModule("/users");
  
  users.addPath("/", (req, res) => {
    res.sendJson({ users: [] }, 200);
  }, { methods: ["GET"] });
  
  users.addPath("/<int:id>", (req, res) => {
    const userId = req.params.id;
    res.sendJson({ id: userId }, 200);
  }, { methods: ["GET"] });
}

routes/posts.ts

import { RouteModule } from "@asimilation/core";

export function setupPostRoutes(parent: RouteModule) {
  const posts = parent.createRouteModule("/posts");
  
  posts.addPath("/", (req, res) => {
    res.sendJson({ posts: [] }, 200);
  }, { methods: ["GET"] });
  
  posts.addPath("/<slug:slug>", (req, res) => {
    const slug = req.params.slug;
    res.sendJson({ slug }, 200);
  }, { methods: ["GET"] });
}

routes/index.ts

import { url } from "@asimilation/core";
import { setupUserRoutes } from "./users.js";
import { setupPostRoutes } from "./posts.js";

const apiModule = url.createRouteModule("/api");

setupUserRoutes(apiModule);
setupPostRoutes(apiModule);

export { apiModule };

main.ts

import { asi } from "@asimilation/core";
import "./routes/index.js";

asi.setup(3000, import.meta.url);
asi.run();

Middlewares with Modules

Apply middlewares to specific module routes:
const apiModule = url.createRouteModule("/api");

// Authentication middleware
const requireAuth = (req, res, next) => {
  if (!req.headers.authorization) {
    res.sendJson({ error: "Unauthorized" }, 401);
    return;
  }
  next();
};

// Apply middleware to all routes in module
apiModule.addPath("/protected", (req, res) => {
  res.sendJson({ data: "secret" }, 200);
}, {
  handlers: [requireAuth]
});

// Sub-modules inherit no middlewares automatically
// You need to explicitly add them to each route
const usersModule = apiModule.createRouteModule("/users");

usersModule.addPath("/", (req, res) => {
  res.sendJson({ users: [] }, 200);
}, {
  handlers: [requireAuth] // Explicitly add middleware
});
Middlewares are not inherited by sub-modules. You need to explicitly specify middlewares for each route or use global middlewares.

Dynamic Routes in Modules

Modules support all route parameter types:
const apiModule = url.createRouteModule("/api");

// Integer parameter
apiModule.addPath("/users/<int:id>", (req, res) => {
  const userId = req.params.id;
  res.sendJson({ userId }, 200);
});

// String parameter
apiModule.addPath("/hello/<string:name>", (req, res) => {
  const name = req.params.name;
  res.sendText(`Hello ${name}!`, 200);
});

// Slug parameter
apiModule.addPath("/posts/<slug:slug>", (req, res) => {
  const slug = req.params.slug;
  res.sendJson({ slug }, 200);
});

// Boolean parameter
apiModule.addPath("/settings/<boolean:enabled>", (req, res) => {
  const enabled = req.params.enabled;
  res.sendJson({ enabled }, 200);
});

// Multiple parameters
apiModule.addPath("/<string:resource>/<int:id>", (req, res) => {
  const { resource, id } = req.params;
  res.sendJson({ resource, id }, 200);
});

How It Works

When you create a route module (see router-manager.ts:148-150 and 154-172):
1

Store Reference

The module stores a reference to the parent RouteManager and the namespace path.
2

Normalize Namespace

The namespace is normalized using normalizePath() (router-manager.ts:161).
3

Prefix Routes

When adding a path, the module’s namespace is prepended to the route path (router-manager.ts:165).
4

Register with Manager

The complete path is registered with the parent RouteManager (router-manager.ts:166).
5

Support Nesting

Modules can create sub-modules by combining namespaces (router-manager.ts:169-171).

Implementation Details

The RouteModule class is simple but powerful:
class RouteModule {
  #manager: RouteManager;
  #initialPath: string;

  constructor(manager: RouteManager, nameSpace: string) {
    this.#manager = manager;
    this.#initialPath = normalizePath(nameSpace);
  }

  addPath(path: string, callback: Controller, kwargs?: PathKwargs) {
    // Combine module namespace with route path
    const contextPath = this.#initialPath + normalizePath(path);
    // Register with the main manager
    this.#manager.addPath(contextPath, callback, kwargs);
  }

  createRouteModule(name: string) {
    // Create nested module by combining namespaces
    return new RouteModule(
      this.#manager,
      this.#initialPath + normalizePath(name)
    );
  }
}
From router-manager.ts:154-172.

Best Practices

Group related routes

Use modules to group routes that belong to the same feature or resource.

Keep namespaces short

Use concise, descriptive namespace names like /api, /admin, /v1.

Separate into files

Split large modules into separate files for better maintainability.

Version your APIs

Use modules to create versioned API endpoints like /api/v1 and /api/v2.

Common Patterns

Admin Dashboard

const adminModule = url.createRouteModule("/admin");

const requireAdmin = (req, res, next) => {
  // Check admin permissions
  next();
};

adminModule.addPath("/dashboard", (req, res) => {
  res.sendJson({ stats: {} }, 200);
}, { handlers: [requireAdmin] });

adminModule.addPath("/users", (req, res) => {
  res.sendJson({ users: [] }, 200);
}, { handlers: [requireAdmin] });

Multi-tenant Application

const tenantModule = url.createRouteModule("/tenant");

tenantModule.addPath("/<string:tenantId>/dashboard", (req, res) => {
  const tenantId = req.params.tenantId;
  res.sendJson({ tenant: tenantId }, 200);
});

tenantModule.addPath("/<string:tenantId>/users", (req, res) => {
  const tenantId = req.params.tenantId;
  res.sendJson({ tenant: tenantId, users: [] }, 200);
});

Microservices Architecture

// User service routes
const userServiceModule = url.createRouteModule("/services/users");
userServiceModule.addPath("/", getUsersHandler);

// Order service routes
const orderServiceModule = url.createRouteModule("/services/orders");
orderServiceModule.addPath("/", getOrdersHandler);

// Product service routes
const productServiceModule = url.createRouteModule("/services/products");
productServiceModule.addPath("/", getProductsHandler);

Next Steps

Routing

Learn more about route parameters and path matching

Middlewares

Discover how to apply middlewares to module routes