Controller-Based Routing
Alapa provides a streamlined approach to implement controller-based routing, enabling developers to define routes in a structured and maintainable manner. This method leverages class methods to automatically generate routes based on naming conventions, reducing boilerplate code and enhancing readability.
Creating Controller-Based Routing
Controller-based routing in Alapa is designed to be intuitive. By following camel-case naming conventions for methods within a controller class, the framework automatically interprets the method names to generate corresponding routes. The first part of the method name specifies the HTTP verb, while the remaining parts define the route path, segmented by uppercase letters.
Example:
Below is an example of a controller class with method-based routing:
import { Controller, Request, Response, Params } from "alapa";
export class UserController extends Controller {
// Handles GET /users
getIndex(req: Request, res: Response) {
res.send("Welcome to the user dashboard");
}
// Handles GET /users/user/:userId
@Params("userId")
getUser(req: Request, res: Response) {
res.send(`User ID: ${req.params.userId}`);
}
}
Registering the Controller with Routes
To integrate the controller with the application's routing system, use the controller
method provided by the Router class. This method maps the controller methods to their respective routes.
import { Router } from "alapa";
import { UserController } from "./Controller";
const userRoute = new Router();
userRoute.controller("users", UserController);
export default userRoute;
The above setup generates the following routes:
HTTP Method | Route Path | Route Name |
---|---|---|
GET | /users | users.index |
GET | /users/user/:userId | users.user |
Supported HTTP Verbs
Alapa supports a variety of HTTP verbs, each corresponding to a specific HTTP method. Below is a list of available verbs and their associated HTTP methods:
- get: Generates a GET route.
- post: Generates a POST route.
- put: Generates a PUT route.
- patch: Generates a PATCH route.
- delete: Generates a DELETE route.
- head: Generates a HEAD route.
- use: Generates a middleware route.
- all: Generates a route that matches all HTTP methods.
When using verbs with the Index
suffix, the Index
part is omitted from the route path.
For example, getIndex
generates a route for /users
instead of /users/index
.
Controller Configuration Options
Alapa provides several options to customize controller-based routing. These options allow you to tailor the routing behavior to suit your application's needs.
Option Name | Type | Optional | Default Value | Description |
---|---|---|---|---|
namePrefix | string | Yes | undefined | Prefix added to the route names. |
docPrefix | string | Yes | Global docPrefix from config | Prefix added to the API documentation path. |
middlewareAll | array | Yes | [] | Middleware applied to all routes in the controller. |
middleware | object | Yes | {} | Middleware applied to specific routes, keyed by method name. |
Example: Using namePrefix
import { Router } from "alapa";
import { UserController } from "./Controller";
const userRoute = new Router();
userRoute.controller("users", UserController, { namePrefix: "app-users" });
export default userRoute;
This configuration modifies the route names as follows:
HTTP Method | Route Path | Route Name |
---|---|---|
GET | /users | app-users.index |
GET | /users/user/:userId | app-users.user |
Example: Using docPrefix
The docPrefix
option is particularly useful for versioning your API documentation.
It prepends the specified prefix to the API paths in the generated Swagger documentation.
import { Router } from "alapa";
import { UserController } from "./Controller";
const userRoute = new Router();
userRoute.controller("users", UserController, { docPrefix: "api/v1" });
export default userRoute;
This results in the following API documentation paths:
HTTP Method | Route Path | Documentation Path |
---|---|---|
GET | /users | api/v1/users |
GET | /users/user/:userId | api/v1/users/{userId} |
Alternatively, you can define the docPrefix
directly within the controller class:
import { Controller, Request, Response, Params } from "alapa";
export class UserController extends Controller {
docPrefix: string = "api/v1/";
}
Example: Applying Middleware
Middleware can be applied globally to all routes within a controller or selectively to specific routes.
Global Middleware (middlewareAll
)
import { Router } from "alapa";
import { UserController } from "./Controller";
import { userMiddleware } from "../middleware";
const userRoute = new Router();
userRoute.controller("users", UserController, {
middlewareAll: [userMiddleware],
});
export default userRoute;
Route-Specific Middleware (middleware
)
import { Router } from "alapa";
import { UserController } from "./Controller";
import { indexMiddleware } from "../middleware";
const userRoute = new Router();
userRoute.controller("users", UserController, {
middleware: {
getIndex: indexMiddleware,
},
});
export default userRoute;
Defining Middleware Within the Controller
Middleware can also be defined directly within the controller class. This approach centralizes route-specific logic, making it easier to manage.
import { Controller, Request, Response, NextFunction } from "alapa";
export class UserController extends Controller {
// Middleware for /users
useIndex(req: Request, res: Response, next: NextFunction) {
console.log("Middleware for /users");
next();
}
// Middleware for /users/user
useUser(req: Request, res: Response, next: NextFunction) {
console.log("Middleware for /users/user");
next();
}
}
Adding Path Parameters
Path parameters can be added using the @Params
decorator.
This decorator allows you to define dynamic segments in your routes.
import { Controller, Request, Response, Params } from "alapa";
export class PostController extends Controller {
// Handles GET /posts/post/:postId/:userId
@Params("postId", "userId")
getPost(req: Request, res: Response) {
res.send(`Post ID: ${req.params.postId}, User ID: ${req.params.userId}`);
}
}
Manipulating Route Paths
The @Params
decorator can also be used to customize route paths.
By using forward slashes (/
), you can structure the URL as needed.
import { Controller, Request, Response, Params } from "alapa";
export class PostController extends Controller {
// Handles GET /posts/post/:postId/user/:userId
@Params("postId/user", "userId")
getPost(req: Request, res: Response) {
res.send(`Post ID: ${req.params.postId}, User ID: ${req.params.userId}`);
}
// Handles GET /posts/:postId/user/:userId/all-posts
@Params("postId/user", "userId/all-posts")
getIndex(req: Request, res: Response) {
res.send("All posts for the user");
}
}
Handling Method Name Conflicts
In scenarios where method names conflict (e.g., multiple middlewares with the same name handling
different operations but pointing to the same path), you can use underscores (_
) in the method names.
Alapa ignores underscores when generating routes
import { Controller, Request, Response, Params } from "alapa";
export class PostController extends Controller {
// Handles GET /posts/:postId/active
@Params("postId/active")
get_Index(req: Request, res: Response) {
res.send("Active posts");
}
// Handles GET /posts/:postId/draft
@Params("postId/draft")
get_Index_(req: Request, res: Response) {
res.send("Draft posts");
}
// Handles GET /posts/:postId/trashed
@Params("postId/trashed")
get___Index___(req: Request, res: Response) {
res.send("Trashed posts");
}
}
The @Params
decorator is a powerful tool for customizing route paths.
It allows you to dynamically structure URLs, making your routing more flexible and expressive.