Express is one of the most popular web frameworks for Node.js that supports routing, middleware, view system... In this tutorial, I will show you how to build Node.js Rest Api example using Express and Typescript.
Related Posts:
Express Typescript example
We will build Node.js Rest Api using Typescript that handles GET/POST/PUT/DELETE Http requests.
First, we start with an Express web server. Next, we write the controller. Then we define routes for handling all CRUD operations:
The following table shows overview of the Rest APIs that will be exported:
Methods | Urls | Actions |
---|---|---|
GET | api/tutorials | get all Tutorials |
GET | api/tutorials/:id | get Tutorial by id
|
POST | api/tutorials | add new Tutorial |
PUT | api/tutorials/:id | update Tutorial by id
|
DELETE | api/tutorials/:id | remove Tutorial by id
|
Finally, we're gonna test the Express Typescript Rest Api using Postman.
Our project structure will be like this:
Create Node.js Typescript application
Open terminal/console, then create a folder for our application:
$ mkdir express-typescript-example
$ cd express-typescript-example
Initialize the Node.js application with a package.json file:
npm init
package name: (express-typescript-example) express-typescript-example
version: (1.0.0)
description: Rest API using Node.js, TypeScript, Express
entry point: (index.js) server.js
test command:
git repository:
keywords: nodejs, typescript, express, restapi, rest api, crud
author: bezkoder
license: (ISC)
About to write to D:\Projects\NodeTs\node-js-typescript-express-mysql\package.json:
{
"name": "express-typescript-example",
"version": "1.0.0",
"description": "Rest API using Node.js, TypeScript, Express",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"nodejs",
"typescript",
"express",
"restapi",
"rest",
"api",
"crud"
],
"author": "bezkoder",
"license": "ISC"
}
Is this OK? (yes)
Add Express and Typescript into Node.js Project
We need to install necessary modules: express
, typescript
, cors
, ts-node
, @types/node
, @types/express
and @types/cors
.
Run the command:
npm install typescript ts-node @types/node @types/express @types/cors --save-dev
npm install express cors
The package.json file should look like this:
{
"name": "express-typescript-example",
"version": "1.0.0",
"description": "Rest API using Node.js, TypeScript, Express",
"main": "server.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"express",
"typescript",
"rest",
"api",
"restapi",
"node",
"nodejs",
"crud"
],
"author": "bezkoder",
"license": "ISC",
"devDependencies": {
"@types/cors": "^2.8.13",
"@types/express": "^4.17.17",
"@types/node": "^20.3.3",
"ts-node": "^10.9.1",
"typescript": "^5.1.6"
},
"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.2"
}
}
Next, we generate a tsconfig.json file with command:
./node_modules/.bin/tsc --init
Open tsconfig.json and modify the content like this:
{
"compilerOptions": {
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
"emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"resolveJsonModule": true, /* Enable importing .json files. */
/* Emit */
"outDir": "./build", /* Specify an output folder for all emitted files. */
/* Interop Constraints */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
/* Completeness */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}
To work with TypeScript, we need TypeScript compiler (tsc), which converts TypeScript code into JavaScript (inside ./build
folder). TypeScript files have the .ts extension. Once compiled to JavaScript, we can run the resulting JavaScript files using a JavaScript runtime environment or include them in web applications.
So we modify "scripts"
property of package.json file by adding build
, dev
and start
like this:
{
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc",
"dev": "node ./build/server.js",
"start": "tsc && npm run dev"
}
...
}
Create Express Typescript server
In src folder, create index.ts file that export Server
class.
import express, { Application } from "express";
import cors, { CorsOptions } from "cors";
export default class Server {
constructor(app: Application) {
this.config(app);
}
private config(app: Application): void {
const corsOptions: CorsOptions = {
origin: "http://localhost:8081"
};
app.use(cors(corsOptions));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
}
}
What we do are:
- import
express
, andcors
modules:- Express is for building the Rest Apis
- cors provides Express middleware to enable CORS with various options.
- define
constructor()
method that receives ExpressApplication
object as parameter. - in
constructor()
, we callconfig()
method that adds body-parser (json
andurlencoded
) andcors
middlewares usingapp.use()
method. Notice that we set origin:http://localhost:8081
.
We continue to create server.ts outside the src folder.
import express, { Application } from "express";
import Server from "./src/index";
const app: Application = express();
const server: Server = new Server(app);
const PORT: number = process.env.PORT ? parseInt(process.env.PORT, 10) : 8080;
app
.listen(PORT, "localhost", function () {
console.log(`Server is running on port ${PORT}.`);
})
.on("error", (err: any) => {
if (err.code === "EADDRINUSE") {
console.log("Error: address already in use");
} else {
console.log(err);
}
});
In the code, we:
- create an Express application using
express()
. - initialize a
Server
object with anApplication
object - listen on port 8080 for incoming requests.
Let's run the app with command: npm run start
.
$ npm run start
> express-typescript-example@1.0.0 start
> tsc && npm run dev
> express-typescript-example@1.0.0 dev
> node ./build/server.js
Server is running on port 8080.
Working with Express Router in Typescript
To handle HTTP requests, we create a new Router
object using express.Router()
function.
In src/routes folder, create home.routes.ts file that exports Router
object.
import { Router } from "express";
import { welcome } from "../controllers/home.controller";
class HomeRoutes {
router = Router();
constructor() {
this.intializeRoutes();
}
intializeRoutes() {
this.router.get("/", welcome);
}
}
export default new HomeRoutes().router;
router.get("/", welcome)
is for handling Http GET requests with welcome
as handler function.
In src/controllers/home.controller.ts, we export welcome
function.
import { Request, Response } from "express";
export function welcome(req: Request, res: Response): Response {
return res.json({ message: "Welcome to bezkoder application." });
}
Next we create Routes
class in src/routes/index.ts.
import { Application } from "express";
import homeRoutes from "./home.routes";
export default class Routes {
constructor(app: Application) {
app.use("/api", homeRoutes);
}
}
Then we import Routes
into Server
class's constructor()
method and initialize a new Routes
object.
// ...
import Routes from "./routes";
export default class Server {
constructor(app: Application) {
this.config(app);
new Routes(app);
}
private config(app: Application): void {
// ...
}
}
Let's stop and re-start the server. Open your browser with url http://localhost:8080/api, you will see:
Handling GET-POST-PUT-DELETE requests with Express Typescript
Now we implement more routes to Routes
class that follows APIs:
Methods | Urls | Actions |
---|---|---|
GET | api/tutorials | get all Tutorials |
GET | api/tutorials/:id | get Tutorial by id
|
POST | api/tutorials | add new Tutorial |
PUT | api/tutorials/:id | update Tutorial by id
|
DELETE | api/tutorials/:id | remove Tutorial by id
|
In src/routes/index.ts, add middleware function for "/api/tutorials"
endpoint.
import { Application } from "express";
import homeRoutes from "./home.routes";
import tutorialRoutes from "./tutorial.routes";
export default class Routes {
constructor(app: Application) {
app.use("/api", homeRoutes);
app.use("/api/tutorials", tutorialRoutes);
}
}
We continue to define the above TutorialRoutes
class which initializes a TutorialController
object that provides CRUD operation methods. It exports Router
object.
src/routes/tutorial.routes.ts
import { Router } from "express";
import TutorialController from "../controllers/tutorial.controller";
class TutorialRoutes {
router = Router();
controller = new TutorialController();
constructor() {
this.intializeRoutes();
}
intializeRoutes() {
// Create a new Tutorial
this.router.post("/", this.controller.create);
// Retrieve all Tutorials
this.router.get("/", this.controller.findAll);
// Retrieve a single Tutorial with id
this.router.get("/:id", this.controller.findOne);
// Update a Tutorial with id
this.router.put("/:id", this.controller.update);
// Delete a Tutorial with id
this.router.delete("/:id", this.controller.delete);
}
}
export default new TutorialRoutes().router;
In src/controllers/tutorial.controller.ts, we define and export TutorialController
class that has create
, findAll
, findOne
, update
, delete
methods.
import { Request, Response } from "express";
export default class TutorialController {
async create(req: Request, res: Response) {
try {
res.status(201).json({
message: "create OK",
reqBody: req.body
});
} catch (err) {
res.status(500).json({
message: "Internal Server Error!"
});
}
}
async findAll(req: Request, res: Response) {
try {
res.status(200).json({
message: "findAll OK"
});
} catch (err) {
res.status(500).json({
message: "Internal Server Error!"
});
}
}
async findOne(req: Request, res: Response) {
try {
res.status(200).json({
message: "findOne OK",
reqParamId: req.params.id
});
} catch (err) {
res.status(500).json({
message: "Internal Server Error!"
});
}
}
async update(req: Request, res: Response) {
try {
res.status(200).json({
message: "update OK",
reqParamId: req.params.id,
reqBody: req.body
});
} catch (err) {
res.status(500).json({
message: "Internal Server Error!"
});
}
}
async delete(req: Request, res: Response) {
try {
res.status(200).json({
message: "delete OK",
reqParamId: req.params.id
});
} catch (err) {
res.status(500).json({
message: "Internal Server Error!"
});
}
}
}
Run and Check
Run the Node.js Express Typescript Rest APIs with command:
npm run start
Conclusion
Today, we've learned how to create Node.js Rest Apis with an Express Typescript web server. We also know way to write a controller and define routes for handling all CRUD operations.
Happy learning! See you again.
Further Reading
File Upload Rest API:
- Node.js Express File Upload Rest API example using Multer
- Google Cloud Storage with Node.js: File Upload example
Source code
You can find the complete source code for this example on Github.
With Database: