Home > Web Front-end > JS Tutorial > Custom error handling in a REST API using TypeScript, Express.js, Joi validation, and object-oriented programming

Custom error handling in a REST API using TypeScript, Express.js, Joi validation, and object-oriented programming

WBOY
Release: 2024-07-27 20:41:12
Original
1137 people have browsed it

Custom error handling in a REST API using TypeScript, Express.js, Joi validation, and object-oriented programming

Hi, Devs!

Building a robust and maintainable REST API requires careful consideration of error handling, validation, and structure. In this article, we'll explore how to set up a custom error handling mechanism in a REST API using TypeScript, Express.js, Joi for validation, and principles of object-oriented programming (OOP). We'll structure our project as follows:

Scructure:

---src
-----middlewares
--------ErrorHanlder.ts
-----models
--------User.ts
-----repository
--------UserRepository.ts
-----routes
--------UserRouter.ts
-----controllers
--------UserController.ts
-----services
--------UserService.ts
-----validations
--------UserValidation.ts
---app.ts
---server.ts

Setting Up the Project

1

2

3

4

5

mkdir rest-api

cd rest-api

npm init -y

npm install express typescript @types/node @types/express ts-node-dev

npx tsc --init

Copy after login

Middleware for Error Handling

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

// src/middlewares/ErrorHandler.ts

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

 

class ErrorHandler extends Error {

  statusCode: number;

  message: string;

 

  constructor(statusCode: number, message: string) {

    super();

    this.statusCode = statusCode;

    this.message = message;

  }

}

 

const handleError = (err: ErrorHandler, req: Request, res: Response, next: NextFunction) => {

  const { statusCode, message } = err;

  res.status(statusCode).json({

    status: 'error',

    statusCode,

    message,

  });

};

 

export { ErrorHandler, handleError };

Copy after login

User Model

1

2

3

4

5

6

// src/models/User.ts

export interface User {

  id: number;

  name: string;

  email: string;

}

Copy after login

User Repository

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// src/repository/UserRepository.ts

import { User } from '../models/User';

 

class UserRepository {

  private users: User[] = [];

 

  findAll(): User[] {

    return this.users;

  }

 

  findById(id: number): User | undefined {

    return this.users.find(user => user.id === id);

  }

 

  create(user: User): User {

    this.users.push(user);

    return user;

  }

}

 

export default new UserRepository();

Copy after login

User Service

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

// src/services/UserService.ts

import UserRepository from '../repository/UserRepository';

import { User } from '../models/User';

import { ErrorHandler } from '../middlewares/ErrorHandler';

 

class UserService {

  getAllUsers(): User[] {

    return UserRepository.findAll();

  }

 

  getUserById(id: number): User | undefined {

    const user = UserRepository.findById(id);

    if (!user) {

      throw new ErrorHandler(404, 'User not found');

    }

    return user;

  }

 

  createUser(user: User): User {

    const { error } = userSchema.validate(user);

    if (error) {

      throw new ErrorHandler(400, error.details[0].message);

    }

    return UserRepository.create(user);

  }

}

 

export default new UserService();

Copy after login

User Validation

1

2

3

4

5

6

7

8

9

10

// src/validations/UserValidation.ts

import Joi from 'joi';

 

const userSchema = Joi.object({

  id: Joi.number().required(),

  name: Joi.string().required(),

  email: Joi.string().email().required(),

});

 

export { userSchema };

Copy after login

User Controller

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

// src/controllers/UserController.ts

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

import UserService from '../services/UserService';

import { ErrorHandler } from '../middlewares/ErrorHandler';

 

class UserController {

  getAllUsers(req: Request, res: Response, next: NextFunction) {

    try {

      const users = UserService.getAllUsers();

      res.json(users);

    } catch (error) {

      next(error);

    }

  }

 

  getUserById(req: Request, res: Response, next: NextFunction) {

    try {

      const user = UserService.getUserById(parseInt(req.params.id));

      res.json(user);

    } catch (error) {

      next(error);

    }

  }

 

  createUser(req: Request, res: Response, next: NextFunction) {

    try {

      const user = UserService.createUser(req.body);

      res.status(201).json(user);

    } catch (error) {

      next(error);

    }

  }

}

 

export default new UserController();

Copy after login

User Routes

1

2

3

4

5

6

7

8

9

10

11

// src/routes/UserRouter.ts

import { Router } from 'express';

import UserController from '../controllers/UserController';

 

const router = Router();

 

router.get('/users', UserController.getAllUsers);

router.get('/users/:id', UserController.getUserById);

router.post('/users', UserController.createUser);

 

export default router;

Copy after login

Application Entry Point

1

2

3

4

5

6

7

8

9

10

11

12

// src/app.ts

import express from 'express';

import UserRouter from './routes/UserRouter';

import { handleError } from './middlewares/ErrorHandler';

 

const app = express();

 

app.use(express.json());

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

app.use(handleError);

 

export default app;

Copy after login

Server Setup

1

2

3

4

5

6

7

8

// src/server.ts

import app from './app';

 

const PORT = process.env.PORT || 3000;

 

app.listen(PORT, () => {

  console.log(`Server running on port ${PORT}`);

});

Copy after login

By structuring our project using TypeScript, Express.js, Joi, and OOP principles, we achieve a clean and maintainable codebase. The custom error handling middleware provides a consistent way to manage errors across the application, while the validation logic ensures data integrity. This setup can serve as a solid foundation for more complex applications.

Contacts
Email: luizcalaca@gmail.com
Instagram: https://www.instagram.com/luizcalaca
Linkedin: https://www.linkedin.com/in/luizcalaca/
Twitter: https://twitter.com/luizcalaca

The above is the detailed content of Custom error handling in a REST API using TypeScript, Express.js, Joi validation, and object-oriented programming. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template