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:
Top comments (0)