Node.js

Building a REST API with Node.js, Express, and TypeScript

Learn how to build a type-safe and robust REST API from scratch using Express.js and TypeScript. This guide covers setup, routing, and validation.

June 8, 2025
4 min read
By useLines Team
Node.jsExpressTypeScriptAPIBackend
Illustration for Building a REST API with Node.js, Express, and TypeScript

Why Use TypeScript with Node.js and Express?

Combining TypeScript with Node.js and Express brings the benefits of static typing to your backend development. This means better autocompletion, less runtime errors, and more maintainable code, especially in large applications. TypeScript helps you catch errors early in the development process and makes your API's data structures explicit and easy to understand.

Project Setup

Let's start by setting up a new Node.js project.

  1. Initialize your project:

    mkdir express-ts-api
    cd express-ts-api
    npm init -y
    
  2. Install dependencies: We'll need Express for the server and TypeScript as a development dependency.

    npm install express
    npm install typescript ts-node @types/node @types/express --save-dev
    
  3. Initialize TypeScript: Create a tsconfig.json file to configure the TypeScript compiler.

    npx tsc --init
    

    For a good starting configuration, you can use the following in your tsconfig.json:

    {
      "compilerOptions": {
        "target": "es6",
        "module": "commonjs",
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true
      }
    }
    

Creating a Basic Server

Now, let's create a src directory and an index.ts file inside it for our server's entry point.

// src/index.ts
import express, { Request, Response } from 'express';

const app = express();
const port = 3000;

app.get('/', (req: Request, res: Response) => {
  res.send('Hello, TypeScript with Express!');
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

To run your server, you can add a script to your package.json:

"scripts": {
  "start": "ts-node src/index.ts"
}

Now, you can run npm start in your terminal and visit http://localhost:3000 in your browser.

Structuring Your API

For a scalable API, it's a good practice to separate your concerns. A common structure is to have separate directories for routes, controllers, and services.

  • routes: Define the API endpoints.
  • controllers: Handle the request and response logic.
  • services: Contain the business logic.

Example: A Simple User API

Let's create a simple API to manage a list of users.

1. User Controller (src/controllers/userController.ts)

import { Request, Response } from 'express';

interface User {
  id: number;
  name: string;
}

let users: User[] = [
  { id: 1, name: 'John Doe' },
  { id: 2, name: 'Jane Doe' },
];

export const getUsers = (req: Request, res: Response) => {
  res.json(users);
};

export const createUser = (req: Request, res: Response) => {
  const newUser: User = {
    id: users.length + 1,
    name: req.body.name,
  };
  users.push(newUser);
  res.status(201).json(newUser);
};

2. User Routes (src/routes/userRoutes.ts)

import { Router } from 'express';
import { getUsers, createUser } from '../controllers/userController';

const router = Router();

router.get('/users', getUsers);
router.post('/users', createUser);

export default router;

3. Update index.ts to use the router and middleware

We need express.json() middleware to parse the request body.

// src/index.ts
import express from 'express';
import userRoutes from './routes/userRoutes';

const app = express();
const port = 3000;

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

app.use('/api', userRoutes);

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

Now you have a structured and type-safe API. You can test your endpoints using a tool like Postman or curl.

This foundation provides a solid starting point for building more complex and robust REST APIs with Node.js, Express, and TypeScript, ensuring your backend code is scalable and maintainable.

Related Posts