DEV Community

Cover image for Mastering Routing in Express with TypeScript
William Onyejiaka
William Onyejiaka

Posted on

Mastering Routing in Express with TypeScript

Routing is a core concept in web development, enabling your application to handle different HTTP requests at specific endpoints. In this blog, we’ll explore how to implement routing in an Express application using TypeScript, leveraging type safety to build robust APIs. By the end, you’ll understand how to create, organize, and manage routes effectively.


What is Routing in Express?

In Express, routing refers to how an application responds to client requests based on the HTTP method (e.g., GET, POST, PUT, DELETE) and URL path. Each route maps to a specific handler function that processes the request and sends a response.
With TypeScript, we can add type safety to our routes, ensuring that request and response objects are properly typed, reducing errors and improving maintainability.


Prerequisites

  • Node.js (v16 or higher)

  • Basic knowledge of Express and TypeScript

  • Code editor (e.g., VS Code)


Step 1: Set Up the Project

  1. Initialize the project:

Create a new directory and set up a Node.js project:

mkdir express-ts-routing
cd express-ts-routing
npm init -y
Enter fullscreen mode Exit fullscreen mode
  1. Install dependencies:

Install Express, TypeScript, and necessary type definitions:

npm install express
npm install --save-dev nodemon typescript ts-node @types/express @types/node
Enter fullscreen mode Exit fullscreen mode
  1. Set up TypeScript:

Initialize TypeScript configuration:

npx tsc --init
Enter fullscreen mode Exit fullscreen mode

Update tsconfig.json to include:

{
   "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true
  },
}
Enter fullscreen mode Exit fullscreen mode
  1. Configure scripts:

Update package.json with:

"scripts": {
  "start": "node dist/server.js",
  "build": "tsc p .",
  "dev": "nodemon src/server.ts"
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Project Structure

Organize your project for scalability:

express-ts-routing/
├── src/
│   ├── routes/
│   │   ├── userRoutes.ts
│   │   └── postRoutes.ts
│   ├── server.ts
├── package.json
├── tsconfig.json
Enter fullscreen mode Exit fullscreen mode

Step 3: Create the Express Server

Create src/server.ts to set up the Express server:

import express, { Application } from 'express';

const app: Application = express();
const PORT = 3000;

// Enable URL-encoded form data parsing
app.use(express.urlencoded({ extended: true }));

// Middleware to parse JSON
app.use(express.json());

// Basic route
app.get('/', (req, res) => {
  res.send('Welcome to the Express TypeScript API!');
});

// Start server
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Enter fullscreen mode Exit fullscreen mode

Here, we initialize an Express app, apply URL-encoded middleware for parsing form data and JSON middleware.


Step 4: Define Routes with TypeScript

User Routes

Create src/routes/userRoutes.ts for user-related endpoints:

import express, { Router, Request, Response } from 'express';

const userRouter: Router = express.Router();

// GET: Fetch all users
userRouter.get('/', (req: Request, res: Response) => {
  res.json({ message: 'List of users', users: [] });
});

// GET: Fetch a user by ID
userRouter.get('/:id', (req: Request, res: Response) => {
  const id = req.params.id;
  res.json({ message: `User with ID ${id}`, user: {} });
});

// POST: Create a user
userRouter.post('/', (req: Request, res: Response) => {
  const { name, email } = req.body;
  res.json({ message: 'User created', user: { name, email } });
});

// PUT: Update a user
userRouter.put('/:id', (req: Request, res: Response) => {
  const id = req.params.id;
  const { name, email } = req.body;
  res.json({ message: `User ${id} updated`, user: { name, email } });
});

// DELETE: Delete a user
userRouter.delete('/:id', (req: Request, res: Response) => {
  const id = req.params.id;
  res.json({ message: `User ${id} deleted` });
});

export default userRouter;
Enter fullscreen mode Exit fullscreen mode

Post Routes

Create src/routes/postRoutes.ts for post-related endpoints:

import express, { Router, Request, Response } from 'express';

const postRouter: Router = express.Router();

// GET: Fetch all posts
postRouter.get('/', (req: Request, res: Response) => {
  res.json({ message: 'List of posts', posts: [] });
});

// GET: Fetch a post by ID
postRouter.get('/:id', (req: Request, res: Response) => {
  const id = req.params.id;
  res.json({ message: `Post with ID ${id}`, post: {} });
});

// POST: Create a post
postRouter.post('/', (req: Request, res: Response) => {
  const { title, content } = req.body;
  res.json({ message: 'Post created', post: { title, content } });
});

export default postRouter;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • Type Safety: The Request and Response types from Express ensure proper typing for request parameters, body, and response methods.

  • Router: The express.Router() method creates modular route handlers, improving code organization.

  • HTTP Methods: Each route handles specific HTTP methods (GET, POST, PUT, DELETE) for CRUD operations.


Step 5: Mount the Routes

We import and mount route modules under specific prefixes (/api/users, /api/posts) in the server.ts file.

Here is the updated server.ts file:

import express, { Application } from 'express';
import userRouter from './routes/userRoutes';
import postRouter from './routes/postRoutes';

const app: Application = express();
const PORT = 3000;

// Enable URL-encoded form data parsing
app.use(express.urlencoded({ extended: true }));

// Middleware to parse JSON
app.use(express.json());

// Mount routes
app.use('/api/users', userRouter);
app.use('/api/posts', postRouter);

// Basic route
app.get('/', (req, res) => {
  res.send('Welcome to the Express TypeScript API!');
});

// Start server
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Enter fullscreen mode Exit fullscreen mode

Step 6: Run the Application

  1. Start the server:

Run the development server:

npm run dev
Enter fullscreen mode Exit fullscreen mode

The server will start on http://localhost:3000.

  1. Test the routes:

Use Postman or cURL to test the endpoints:

  • GET http://localhost:3000/api/users: List all users.

  • POST http://localhost:3000/api/users: Create a user (e.g., { "name": "John", "email": "john@example.com" }).

  • GET http://localhost:3000/api/posts: List all posts.


Enhancements

  • Input Validation: Use express-validator to validate request bodies and query parameters.

  • Authentication: Integrate JWT or OAuth middleware for secure routes.

  • Route Prefixing: Group related routes under a common prefix (e.g., /api/users).

  • Version Your API: Prefix routes with a version (e.g., /api/v1/users) to manage API updates.

  • Documentation: Use tools like Swagger to document your API endpoints.


Conclusion

Routing in Express with TypeScript combines the flexibility of Express with the type safety of TypeScript, resulting in scalable and maintainable APIs. By modularizing routes, typing request/response objects, and following best practices, you can build robust APIs with confidence.
Try extending this setup with a database like MongoDB or adding authentication to secure your routes. Happy coding!

The code for this blog is here.

Top comments (0)