Skip to main content

Basic Routing

Alapa provides a straightforward and flexible routing system for handling HTTP requests. Its routing design is similar to Express, allowing developers to define routes for various HTTP methods easily.


Defining Routes

Routes are defined using the Router class, which maps specific HTTP methods and URLs to handler functions. Below is an example of a basic route definition:

src/app/index.ts
import { Router, Request, Response } from "alapa";

const indexRoute = new Router();

// GET Route
indexRoute.get("/", (req: Request, res: Response) => {
res.send("Welcome to my site!");
});

export default indexRoute;

After Defining index Route you can now connect to application routes as show bellow

src/app/routes.ts
import { Router } from 'alapa'
import indexRoute from './index'

const routes = new Router()

routes.use(indexRoute)

export default routes
When you open the link http://localhost:3000/ in your browser, you should see the result shown below.
http://localhost:3000/
Welcome to my site!

Supported HTTP Methods

Alapa supports all common HTTP methods, such as:

  • GET
  • POST
  • PUT
  • PATCH
  • DELETE
  • OPTIONS
  • ALL

Each method is mapped using a corresponding function (router.get, router.post, etc.).

Example:

untitled
import { Router, Request, Response } from "alapa";
const router = new Router();

// POST Route
router.post("/submit", (req: Request, res: Response) => {
const { name, email } = req.body;
res.send(`Data received: Name: ${name}, Email: ${email}`);
});

// PUT Route
router.put("/update", (req: Request, res: Response) => {
const { id, data } = req.body;
res.send(`Updating record ${id} with data: ${JSON.stringify(data)}`);
});

// All Route
router.all("/login", (req: Request, res: Response) => {
const { user, password } = req.body;
res.send(`The method is ${req.method}`);
});

// DELETE Route
router.delete("/remove/:id", (req: Request, res: Response) => {
const { id } = req.params;
res.send(`Record ${id} has been deleted.`);
});

Route Parameters

Dynamic segments can be added to routes using the : syntax. Parameters are accessible via req.params.

Example:

src/app/users/router.ts
import { Router, Request, Response } from "alapa";
const userRoutes = new Router();

userRoutes.get("/users/:id", (req: Request, res: Response) => {
const id = req.params.id;
res.send(`Fetching details for user with ID: ${id}`);
});
export default userRoutes;

When you open the link http://localhost:3000/users/1 in your browser, you should see the result shown below.
http://localhost:3000/users/1

Fetching details for user with ID: 1

Query Strings

You can handle query strings in routes using req.query.

Example:

src/app/search.ts
router.get("/search", (req: Request, res: Response) => {
const { keyword, page } = req.query;
res.send(`Search results for '${keyword}' on page ${page}`);
});
When you open the link http://localhost:3000/search?keyword=foo&page=2 in your browser, you should see the result shown below.
http://localhost:3000/search?keyword=foo&page=2

Search results for foo on page 2

router.all Route

The all method is a special route handler that matches all HTTP methods (GET, POST, PUT, DELETE, etc.) for a specific route. This is useful when you want to handle multiple types of requests on the same route but with different behavior depending on the HTTP method being used.

How the all Method Works:

  • The router.all("/login", ...) route will match any HTTP method that targets the /login path.
  • Inside the route handler, req.method contains the HTTP method used for that specific request (such as GET, POST, PUT, etc.).
  • This allows you to write a single route handler for multiple methods and handle them dynamically based on the value of req.method.

Example Breakdown:

src/app/account/login.html
router.all("/login", (req: Request, res: Response) => {
const { user, password } = req.body;
res.send(`The method is ${req.method}`);
});
  • Request Handling: This route handler will fire for any HTTP method (GET, POST, PUT, DELETE, etc.) that matches /login.
  • Dynamic Response Based on Method: The req.method value is dynamically injected based on the method that was used to make the request. For example:
    • If the request is a GET, req.method will be "GET".
    • If the request is a POST, req.method will be "POST".
  • The response will simply echo the HTTP method being used in the request.

Use Case of req.method:

  • POST Request: If you send a POST request to /login, the handler will process the login form (using req.body to get the user and password) and return a message like: The method is POST.
  • GET Request: If you send a GET request to /login, it will still match the route, but now req.method will return "GET", and you can decide to return a different message or handle it in a different way.

Example with Different Behavior:

src/app/account/login.html
router.all("/login", (req: Request, res: Response) => {
if (req.method === "POST") {
const { user, password } = req.body;
res.send(`Login submitted with user: ${user}`);
} else if (req.method === "GET") {
res.render("account/login");
} else {
res.send(`Unsupported method: ${req.method}`);
}
});
  • If the method is POST, it will process the login details.
  • If the method is GET, it will render views/account/login.html template.
  • For any other HTTP method (like PUT, DELETE), it will return a message stating the method is unsupported.

Why Use all Route?

The all route is useful when you want to capture all possible HTTP methods for a specific URL and handle them accordingly. However, in many cases, it might be more readable and maintainable to use method-specific routes (e.g., router.get(), router.post(), etc.) when you know you only need to handle one HTTP method at a time.

The all method is more suitable for situations where the behavior needs to vary dynamically based on the method being used.


Default Route (404 Handling)

To handle undefined routes, you can define a fallback route:

src/app/routes.ts
appRouter.all("*", (req: Request, res: Response) => {
res.status(404).send("Page not found");
});

Grouping Routes

Organize your routes by grouping them using separate files or route prefixes.

Example:

src/app/routes.ts
const userRouter = new Router();
userRouter.get("/profile", (req: Request, res: Response) => {
res.send("User profile");
});

const appRouter = new Router();
appRouter.use("/users", userRouter); // This handles routes prefixed with "/users"

export default appRouter;

Now, all routes under userRouter will be prefixed with /users.

When you open the link http://localhost:3000/users/profile in your browser, you should see the result shown below.
http://localhost:3000/users/profile

User profile


Summary

Alapa routing is highly intuitive, enabling developers to handle routes, parameters, query strings, and even custom route grouping with ease.