├── .gitignore ├── src ├── index.ts ├── common │ ├── builder │ │ ├── success-response.builder.ts │ │ └── error-response.builder.ts │ ├── interface │ │ └── route.interface.ts │ └── validator │ │ └── request.validator.ts ├── exception │ ├── interface │ │ └── exception.interface.ts │ ├── app.exception.ts │ ├── response │ │ ├── server.exception.ts │ │ └── client.exception.ts │ ├── custom.exception.ts │ └── handler.exception.ts ├── module │ ├── health │ │ ├── health.controller.ts │ │ └── health.route.ts │ └── post │ │ ├── post.controller.ts │ │ ├── post.route.ts │ │ └── post.schema.ts ├── app.process.ts ├── app.exit.ts ├── app.ts └── routes │ └── app.route.ts ├── tsconfig.json ├── package.json ├── README.md └── express-exception-handling.postman_collection.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import "express-async-errors"; 2 | import "./app"; 3 | -------------------------------------------------------------------------------- /src/common/builder/success-response.builder.ts: -------------------------------------------------------------------------------- 1 | const SuccessResponse = (statusCode: number, payload: any) => { 2 | return { statusCode, payload }; 3 | }; 4 | 5 | export default SuccessResponse; -------------------------------------------------------------------------------- /src/common/interface/route.interface.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | interface IRouter { 4 | readonly path: string; 5 | readonly router: Router; 6 | initRoute(): void; 7 | } 8 | 9 | export default IRouter; -------------------------------------------------------------------------------- /src/exception/interface/exception.interface.ts: -------------------------------------------------------------------------------- 1 | export interface ICustomExceptionArgs { 2 | errorCode: number; 3 | errorName: string; 4 | errorMessage: string; 5 | errorRawMessage?: unknown; 6 | errorOperational?: boolean; 7 | } 8 | -------------------------------------------------------------------------------- /src/module/health/health.controller.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | 3 | class HealthCheckController { 4 | public getHealth = (req: Request, res: Response): void => { 5 | res.status(200).json({ status: 'healthy' }); 6 | }; 7 | } 8 | 9 | export default HealthCheckController; 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "target": "es2017", 5 | "outDir": "./dist", 6 | "baseUrl": "./src", 7 | "alwaysStrict": true, 8 | "noImplicitAny": true, 9 | "esModuleInterop": true, 10 | "moduleResolution": "Node16" 11 | }, 12 | "include": [ 13 | "src/**/*.ts" 14 | ], 15 | "exclude": [ 16 | "node_modules" 17 | ] 18 | } -------------------------------------------------------------------------------- /src/exception/app.exception.ts: -------------------------------------------------------------------------------- 1 | import { Application, NextFunction, Request, Response } from 'express'; 2 | 3 | import HandlerException from './handler.exception'; 4 | 5 | const AppException = (app: Application) => { 6 | app.use((error: Error, request: Request, response: Response, next: NextFunction) => { 7 | new HandlerException(error, request, response); 8 | }); 9 | } 10 | 11 | export default AppException; -------------------------------------------------------------------------------- /src/common/builder/error-response.builder.ts: -------------------------------------------------------------------------------- 1 | const ErrorResponseBuilder = (output: any) => { 2 | return { 3 | statusCode: output?.statusCode, 4 | payload: { 5 | errorCode: output?.payload?.errorCode, 6 | errorName: output?.payload?.errorName, 7 | errorMessage: output?.payload?.errorMessage, 8 | ...(output?.payload?.errorRawMessage) 9 | && { errorRawMessage: output?.payload?.errorRawMessage } 10 | } 11 | }; 12 | } 13 | 14 | export default ErrorResponseBuilder; -------------------------------------------------------------------------------- /src/exception/response/server.exception.ts: -------------------------------------------------------------------------------- 1 | import status from 'http-status'; 2 | 3 | import CustomException from "../custom.exception" 4 | 5 | export class InternalServeError extends CustomException { 6 | constructor(errorRawMessage?: unknown) { 7 | super({ 8 | errorCode: Number(status['INTERNAL_SERVER_ERROR']), 9 | errorName: String(status[`${status.INTERNAL_SERVER_ERROR}_NAME`]), 10 | errorMessage: String(status[`${status.INTERNAL_SERVER_ERROR}_MESSAGE`]), 11 | errorRawMessage: errorRawMessage 12 | }) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app.process.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | 3 | import appExit from './app.exit'; 4 | 5 | process.on('EACCES', () => { 6 | console.log(`Process ${process.pid} received EACCES`); 7 | appExit(1); 8 | }); 9 | 10 | process.on('EADDRINUSE', () => { 11 | console.log(`Process ${process.pid} received EADDRINUSE`); 12 | appExit(1); 13 | }); 14 | 15 | process.on('SIGTERM', () => { 16 | console.log(`Process ${process.pid} received SIGTERM`); 17 | appExit(0); 18 | }); 19 | 20 | process.on('SIGINT', () => { 21 | console.log(`Process ${process.pid} received SIGINT`); 22 | appExit(0); 23 | }); 24 | -------------------------------------------------------------------------------- /src/module/health/health.route.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | import IRouter from '../../common/interface/route.interface'; 4 | import HealthCheckController from './health.controller'; 5 | 6 | class HealthCheckRoute implements IRouter { 7 | public path = '/health'; 8 | public router = Router(); 9 | public controller: any; 10 | 11 | constructor() { 12 | this.controller = new HealthCheckController(); 13 | this.initRoute(); 14 | } 15 | 16 | public initRoute(): void { 17 | this.router.get(this.path, this.controller.getHealth); 18 | } 19 | 20 | } 21 | export default HealthCheckRoute; -------------------------------------------------------------------------------- /src/app.exit.ts: -------------------------------------------------------------------------------- 1 | import { httpTerminator, server } from './app'; 2 | 3 | const appExit = async (code: number): Promise => { 4 | try { 5 | console.log(`Attempting a graceful shutdown with code ${code}`); 6 | 7 | if (server.listening) { 8 | console.log('Terminating HTTP connections'); 9 | await httpTerminator.terminate(); 10 | } 11 | 12 | console.log(`Exiting gracefully with code ${code}`); 13 | process.exit(code); 14 | } catch (error) { 15 | console.error(`Error shutting down gracefully: ${error}`); 16 | console.error(`Forcing exit with code ${code}`); 17 | process.exit(code); 18 | } 19 | } 20 | 21 | export default appExit; 22 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import http from 'http'; 2 | import cors from 'cors'; 3 | import express, { Application } from 'express'; 4 | import { createHttpTerminator } from 'http-terminator'; 5 | 6 | import './app.process'; 7 | import AppRoute from './routes/app.route'; 8 | import AppException from './exception/app.exception'; 9 | 10 | const app: Application = express(); 11 | 12 | app.use(cors()); 13 | app.use(express.json()); 14 | app.use(express.urlencoded({ extended: true })); 15 | 16 | AppRoute(app); 17 | AppException(app); 18 | 19 | export const server = http.createServer(app); 20 | export const httpTerminator = createHttpTerminator({ server }); 21 | 22 | server.listen(5000, () => { 23 | console.log(`App listening on port 5000`); 24 | }); 25 | -------------------------------------------------------------------------------- /src/common/validator/request.validator.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from 'express'; 2 | import { ZodError, AnyZodObject } from 'zod'; 3 | 4 | import { BadRequest } from '../../exception/response/client.exception'; 5 | 6 | const requestValidator = (schema: AnyZodObject) => 7 | async (request: Request, response: Response, next: NextFunction) => { 8 | try { 9 | await schema.parseAsync({ 10 | body: request.body, 11 | query: request.query, 12 | params: request.params, 13 | }); 14 | return next(); 15 | } catch (error) { 16 | if (error instanceof ZodError) { 17 | throw new BadRequest(error.issues); 18 | } 19 | throw error; 20 | } 21 | }; 22 | 23 | export default requestValidator; 24 | -------------------------------------------------------------------------------- /src/exception/response/client.exception.ts: -------------------------------------------------------------------------------- 1 | import status from 'http-status'; 2 | 3 | import CustomException from '../custom.exception'; 4 | 5 | export class NotFound extends CustomException { 6 | constructor() { 7 | super({ 8 | errorCode: Number(status['NOT_FOUND']), 9 | errorName: String(status[`${status.NOT_FOUND}_NAME`]), 10 | errorMessage: String(status[`${status.NOT_FOUND}_MESSAGE`]) 11 | }) 12 | }; 13 | } 14 | 15 | export class BadRequest extends CustomException { 16 | constructor(errorRawMessage?: unknown) { 17 | super({ 18 | errorCode: Number(status['BAD_REQUEST']), 19 | errorName: String(status[`${status.BAD_REQUEST}_NAME`]), 20 | errorMessage: String(status[`${status.BAD_REQUEST}_MESSAGE`]), 21 | errorRawMessage: errorRawMessage 22 | }) 23 | }; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-exception-handling", 3 | "version": "1.0.0", 4 | "description": "express + exception handling", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "start": "ts-node src/index.ts", 8 | "start:dev": "tsnd --respawn src/index.ts" 9 | }, 10 | "author": "Sudhakar Jonnakuti", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cors": "^2.8.5", 14 | "express": "^4.18.2", 15 | "express-async-errors": "^3.1.1", 16 | "http-status": "^1.6.2", 17 | "http-terminator": "^3.2.0", 18 | "mongoose": "^7.3.1", 19 | "zod": "^3.21.4" 20 | }, 21 | "devDependencies": { 22 | "@types/cors": "^2.8.13", 23 | "@types/express": "^4.17.17", 24 | "@types/node": "^20.3.2", 25 | "ts-node": "^10.9.1", 26 | "ts-node-dev": "^2.0.0", 27 | "typescript": "^5.1.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/routes/app.route.ts: -------------------------------------------------------------------------------- 1 | import { Application, NextFunction, Request, Response } from "express"; 2 | 3 | import HealthCheckRoute from '../module/health/health.route'; 4 | import PostRoute from '../module/post/post.route'; 5 | import { NotFound } from '../exception/response/client.exception'; 6 | 7 | const appModuleRoute = (app: Application) => { 8 | const moduleRoute = () => [ 9 | new HealthCheckRoute(), 10 | new PostRoute() 11 | ]; 12 | 13 | moduleRoute().forEach((appRoute) => { 14 | app.use("/api", appRoute.router); 15 | }); 16 | } 17 | 18 | const appDefaultRoute = (app: Application) => { 19 | app.use("*", (req: Request, res: Response, next: NextFunction) => { 20 | throw new NotFound() 21 | }); 22 | } 23 | 24 | const AppRoute = (app: Application) => { 25 | appModuleRoute(app); 26 | appDefaultRoute(app); 27 | } 28 | 29 | export default AppRoute; 30 | -------------------------------------------------------------------------------- /src/exception/custom.exception.ts: -------------------------------------------------------------------------------- 1 | import { ICustomExceptionArgs } from './interface/exception.interface'; 2 | 3 | class CustomException extends Error { 4 | public readonly errorCode!: number; 5 | public readonly errorName!: string; 6 | public readonly errorMessage!: string; 7 | public readonly errorRawMessage: unknown; 8 | public readonly errorOperational: boolean = true; 9 | 10 | constructor(customExceptionArgs: ICustomExceptionArgs) { 11 | super(customExceptionArgs.errorMessage); 12 | 13 | Object.setPrototypeOf(this, new.target.prototype); 14 | 15 | this.errorCode = customExceptionArgs.errorCode; 16 | this.errorName = customExceptionArgs.errorName; 17 | this.errorMessage = customExceptionArgs.errorMessage; 18 | 19 | if (customExceptionArgs.errorRawMessage) { 20 | this.errorRawMessage = customExceptionArgs.errorRawMessage; 21 | } 22 | 23 | if (customExceptionArgs.errorOperational !== undefined) { 24 | this.errorOperational = customExceptionArgs.errorOperational; 25 | } 26 | 27 | //Error.captureStackTrace(this); 28 | } 29 | 30 | } 31 | 32 | export default CustomException; 33 | -------------------------------------------------------------------------------- /src/module/post/post.controller.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | 3 | import SuccessResponse from '../../common/builder/success-response.builder'; 4 | 5 | class PostController { 6 | 7 | public createPost = (request: Request, response: Response) => { 8 | const postData = request.body; 9 | response.status(200).json(SuccessResponse(200, { postData })); 10 | } 11 | 12 | public getPosts = (request: Request, response: Response) => { 13 | const title = request.query.title; 14 | response.status(200).json(SuccessResponse(200, { title })); 15 | } 16 | 17 | public getPostById = (request: Request, response: Response) => { 18 | const id = request.params.id; 19 | response.status(200).json(SuccessResponse(200, { id })); 20 | } 21 | 22 | public updatePost = (request: Request, response: Response) => { 23 | const id = request.params.id; 24 | const postData = request.body; 25 | response.status(200).json(SuccessResponse(200, { id, postData })); 26 | } 27 | 28 | public deletePost = (request: Request, response: Response) => { 29 | const id = request.params.id; 30 | response.status(200).json(SuccessResponse(200, { id })); 31 | } 32 | 33 | } 34 | 35 | export default PostController; -------------------------------------------------------------------------------- /src/module/post/post.route.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | 3 | import IRouter from '../../common/interface/route.interface'; 4 | import PostController from './post.controller'; 5 | import { createPostSchema, postIdSchema, 6 | postTitleSchema, updatePostSchema } from './post.schema'; 7 | import requestValidator from '../../common/validator/request.validator'; 8 | 9 | class PostRoute implements IRouter { 10 | public path = "/v1/post"; 11 | public router = Router(); 12 | public controller: PostController; 13 | 14 | constructor() { 15 | this.controller = new PostController(); 16 | this.initRoute(); 17 | } 18 | 19 | public initRoute(): void { 20 | this.router.post( 21 | this.path, 22 | requestValidator(createPostSchema), 23 | this.controller.createPost 24 | ); 25 | this.router.get( 26 | this.path, 27 | requestValidator(postTitleSchema), 28 | this.controller.getPosts 29 | ); 30 | this.router.get( 31 | `${this.path}/:id`, 32 | requestValidator(postIdSchema), 33 | this.controller.getPostById 34 | ); 35 | this.router.put( 36 | `${this.path}/:id`, 37 | requestValidator(updatePostSchema), 38 | this.controller.updatePost 39 | ); 40 | this.router.delete( 41 | `${this.path}/:id`, 42 | requestValidator(postIdSchema), 43 | this.controller.deletePost 44 | ); 45 | } 46 | 47 | } 48 | export default PostRoute; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # express-exception-handling 2 | 3 | ``` 4 | Efficient Error Handling in Express.js Made Easy 5 | https://dev.to/franciscomendes10866/easy-peasy-error-handling-in-expressjs-n98 6 | 7 | Sample Error Response - 1 8 | 9 | { 10 | "statusCode": 400, 11 | "payload": { 12 | "errorCode": 400, 13 | "errorName": "BAD_REQUEST", 14 | "errorMessage": "The server cannot or will not process the request due to an apparent client error.", 15 | "errorRawMessage": [ 16 | { 17 | "validation": "url", 18 | "code": "invalid_string", 19 | "message": "Invalid url", 20 | "path": [ 21 | "body", 22 | "url" 23 | ] 24 | }, 25 | { 26 | "code": "invalid_type", 27 | "expected": "string", 28 | "received": "undefined", 29 | "path": [ 30 | "body", 31 | "content" 32 | ], 33 | "message": "The content is required" 34 | } 35 | ] 36 | } 37 | } 38 | 39 | Sample Error Response - 2 40 | 41 | { 42 | "statusCode": 500, 43 | "payload": { 44 | "errorCode": 500, 45 | "errorName": "INTERNAL_SERVER_ERROR", 46 | "errorMessage": "A generic error message, given when an unexpected condition was encountered and no more specific message is suitable.", 47 | "errorRawMessage": "[\n {\n \"validation\": \"url\",\n \"code\": \"invalid_string\",\n \"message\": \"Invalid url\",\n \"path\": [\n \"body\",\n \"url\"\n ]\n },\n {\n \"code\": \"invalid_type\",\n \"expected\": \"string\",\n \"received\": \"undefined\",\n \"path\": [\n \"body\",\n \"content\"\n ],\n \"message\": \"The content is required\"\n }\n]" 48 | } 49 | } 50 | 51 | ``` -------------------------------------------------------------------------------- /src/module/post/post.schema.ts: -------------------------------------------------------------------------------- 1 | import { object, string } from 'zod'; 2 | import mongoose from 'mongoose'; 3 | 4 | export const postTitleSchema = object({ 5 | query: object({ 6 | title: string().nullable().optional() 7 | .refine((val: any) => /^[a-zA-Z]+[-'s]?[a-zA-Z ]+$/.test(val), { 8 | message: 'Please enter a valid title', 9 | }) 10 | }) 11 | }); 12 | 13 | export const postIdSchema = object({ 14 | params: object({ 15 | id: string().optional() 16 | .refine((val: any) => mongoose.isValidObjectId(val), { 17 | message: 'Please enter a valid ObjectId', 18 | }) 19 | }) 20 | }); 21 | 22 | export const createPostSchema = object({ 23 | body: object({ 24 | title: 25 | string({ 26 | required_error: 'The title is required', 27 | }).refine((val: any) => /^[a-zA-Z ]*$/.test(val), { 28 | message: "Please enter a valid title", 29 | }), 30 | author: 31 | string({ 32 | required_error: 'The author is required', 33 | }).refine((val: any) => /^[a-zA-Z ]*$/.test(val), { 34 | message: "Please enter a valid author", 35 | }), 36 | url: string({ required_error: 'The url is required' }).url(), 37 | content: string({ required_error: 'The content is required' }) 38 | }) 39 | }); 40 | 41 | export const updatePostSchema = object({ 42 | params: object({ 43 | id: string().optional() 44 | .refine((val: any) => mongoose.isValidObjectId(val), { 45 | message: 'Please enter a valid ObjectId', 46 | }) 47 | }), 48 | body: object({ 49 | title: string().nullable().optional() 50 | .refine((val: any) => /^[a-zA-Z ]*$/.test(val), { 51 | message: "Please enter a valid title", 52 | }), 53 | author: 54 | string().nullable().optional() 55 | .refine((val: any) => /^[a-zA-Z ]*$/.test(val), { 56 | message: "Please enter a valid author", 57 | }), 58 | url: string().url().nullable().optional(), 59 | content: string().nullable().optional() 60 | }) 61 | }); 62 | -------------------------------------------------------------------------------- /src/exception/handler.exception.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | 3 | import CustomException from './custom.exception'; 4 | import ErrorResponseBuilder from '../common/builder/error-response.builder'; 5 | import { InternalServeError } from './response/server.exception'; 6 | 7 | class HandlerException { 8 | 9 | constructor(error: Error, request: Request, response: Response) { 10 | if (this._isTrustedError(error)) { 11 | this._handleTrustedError(error as CustomException, request, response); 12 | } else { 13 | this._handleUntrustedError(error, request, response); 14 | } 15 | } 16 | 17 | private _isTrustedError(error: Error): boolean { 18 | return error instanceof CustomException ? error.errorOperational : false; 19 | } 20 | 21 | private _handleTrustedError(error: CustomException, request: Request, response: Response): void { 22 | console.log(`[Trusted Exception]: Path: ${request.path}, Method: ${request.method}`); 23 | console.error(`[Trusted Exception]: ${error.stack}`); 24 | this._handleErrorResponse(error, response); 25 | } 26 | 27 | private _normalizeError(error: Error): Error { 28 | if (typeof error === "object" && error instanceof Error) { 29 | return error; 30 | } else if (typeof error === "string") { 31 | return new Error(error); 32 | } 33 | return new Error(JSON.stringify(error)); 34 | } 35 | 36 | private _handleUntrustedError(error: Error, request: Request, response?: Response): void { 37 | console.log(`[Untrusted Exception]: Path: ${request.path}, Method: ${request.method}`); 38 | console.error(`[Untrusted Exception]: ${error.stack}`); 39 | const serialized = this._normalizeError(error).message; 40 | error = new InternalServeError(serialized); 41 | this._handleErrorResponse((error as CustomException), response); 42 | } 43 | 44 | private _handleErrorResponse(error: CustomException, response: Response) { 45 | response.status(error.errorCode).send( 46 | ErrorResponseBuilder({ 47 | statusCode: error.errorCode, 48 | payload: { 49 | errorCode: error.errorCode, 50 | errorName: error.errorName, 51 | errorMessage: error.errorMessage, 52 | ...(error.errorRawMessage) && { errorRawMessage: error.errorRawMessage } 53 | } 54 | }) 55 | ); 56 | } 57 | 58 | } 59 | 60 | export default HandlerException; 61 | -------------------------------------------------------------------------------- /express-exception-handling.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "6abdddda-0d72-4a1f-a4fd-343f288ffc53", 4 | "name": "express-exception-handling", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "01. Health", 10 | "request": { 11 | "method": "GET", 12 | "header": [], 13 | "url": { 14 | "raw": "http://localhost:5000/api/health", 15 | "protocol": "http", 16 | "host": [ 17 | "localhost" 18 | ], 19 | "port": "5000", 20 | "path": [ 21 | "api", 22 | "health" 23 | ] 24 | } 25 | }, 26 | "response": [] 27 | }, 28 | { 29 | "name": "02. Create Post - Success - Api/v1/post/", 30 | "request": { 31 | "method": "POST", 32 | "header": [], 33 | "body": { 34 | "mode": "raw", 35 | "raw": "{\r\n \"title\": \"Hanuman Amar Chitra Katha\",\r\n \"author\": \"Anant Pai\",\r\n \"url\": \"https://zod.dev\",\r\n \"content\": \"Please check content in amazon ebook\"\r\n}", 36 | "options": { 37 | "raw": { 38 | "language": "json" 39 | } 40 | } 41 | }, 42 | "url": { 43 | "raw": "http://localhost:5000/api/v1/post/", 44 | "protocol": "http", 45 | "host": [ 46 | "localhost" 47 | ], 48 | "port": "5000", 49 | "path": [ 50 | "api", 51 | "v1", 52 | "post", 53 | "" 54 | ] 55 | } 56 | }, 57 | "response": [] 58 | }, 59 | { 60 | "name": "03. Create Post - Failure - Api/v1/post/", 61 | "request": { 62 | "method": "POST", 63 | "header": [], 64 | "body": { 65 | "mode": "raw", 66 | "raw": "{\r\n \"title\": \"Hanuman Amar Chitra Katha\",\r\n \"author\": \"Anant Pai\",\r\n \"url\": \"www.amazon.in/Hanuman-1-ANANT-PAI-ebook/dp/B01N1270NX/ref=lp_20912611031_1_3\"\r\n}", 67 | "options": { 68 | "raw": { 69 | "language": "json" 70 | } 71 | } 72 | }, 73 | "url": { 74 | "raw": "http://localhost:5000/api/v1/post", 75 | "protocol": "http", 76 | "host": [ 77 | "localhost" 78 | ], 79 | "port": "5000", 80 | "path": [ 81 | "api", 82 | "v1", 83 | "post" 84 | ] 85 | } 86 | }, 87 | "response": [] 88 | }, 89 | { 90 | "name": "04. Get Posts - Success - api/v1/post?title=", 91 | "request": { 92 | "method": "GET", 93 | "header": [], 94 | "url": { 95 | "raw": "http://localhost:5000/api/v1/post?title=Hanuman Amar Chitra Katha", 96 | "protocol": "http", 97 | "host": [ 98 | "localhost" 99 | ], 100 | "port": "5000", 101 | "path": [ 102 | "api", 103 | "v1", 104 | "post" 105 | ], 106 | "query": [ 107 | { 108 | "key": "title", 109 | "value": "Hanuman Amar Chitra Katha" 110 | } 111 | ] 112 | } 113 | }, 114 | "response": [] 115 | }, 116 | { 117 | "name": "05. Get Posts - failure - api/v1/post?title=", 118 | "request": { 119 | "method": "GET", 120 | "header": [], 121 | "url": { 122 | "raw": "http://localhost:5000/api/v1/post?title=13213", 123 | "protocol": "http", 124 | "host": [ 125 | "localhost" 126 | ], 127 | "port": "5000", 128 | "path": [ 129 | "api", 130 | "v1", 131 | "post" 132 | ], 133 | "query": [ 134 | { 135 | "key": "title", 136 | "value": "13213" 137 | } 138 | ] 139 | } 140 | }, 141 | "response": [] 142 | }, 143 | { 144 | "name": "06. Get Post By Id - Success - api/v1/post/507f1f77bcf86cd799439011", 145 | "request": { 146 | "method": "GET", 147 | "header": [], 148 | "url": { 149 | "raw": "http://localhost:5000/api/v1/post/507f1f77bcf86cd799439011", 150 | "protocol": "http", 151 | "host": [ 152 | "localhost" 153 | ], 154 | "port": "5000", 155 | "path": [ 156 | "api", 157 | "v1", 158 | "post", 159 | "507f1f77bcf86cd799439011" 160 | ] 161 | } 162 | }, 163 | "response": [] 164 | }, 165 | { 166 | "name": "07. Get Post By Id - Failure - api/v1/post/507f1f77bcf86cd", 167 | "request": { 168 | "method": "GET", 169 | "header": [], 170 | "url": { 171 | "raw": "http://localhost:5000/api/v1/post/507f1f77bcf86cd", 172 | "protocol": "http", 173 | "host": [ 174 | "localhost" 175 | ], 176 | "port": "5000", 177 | "path": [ 178 | "api", 179 | "v1", 180 | "post", 181 | "507f1f77bcf86cd" 182 | ] 183 | } 184 | }, 185 | "response": [] 186 | }, 187 | { 188 | "name": "08. Update Post - Success - api/v1/post/507f1f77bcf86cd799439011", 189 | "request": { 190 | "method": "PUT", 191 | "header": [], 192 | "body": { 193 | "mode": "raw", 194 | "raw": "{\r\n \"title\": \"Hanuman Amar Chitra Katha\",\r\n \"author\": \"Anant Pai\"\r\n}", 195 | "options": { 196 | "raw": { 197 | "language": "json" 198 | } 199 | } 200 | }, 201 | "url": { 202 | "raw": "http://localhost:5000/api/v1/post/507f1f77bcf86cd799439011", 203 | "protocol": "http", 204 | "host": [ 205 | "localhost" 206 | ], 207 | "port": "5000", 208 | "path": [ 209 | "api", 210 | "v1", 211 | "post", 212 | "507f1f77bcf86cd799439011" 213 | ] 214 | } 215 | }, 216 | "response": [] 217 | }, 218 | { 219 | "name": "09. Update Post - Failure - api/v1/post/507f1f77bcf86cd7", 220 | "request": { 221 | "method": "PUT", 222 | "header": [], 223 | "body": { 224 | "mode": "raw", 225 | "raw": "{\r\n \"title\": \"Hanuman Amar Chitra Katha\",\r\n \"author\": \"Anant Pai\"\r\n}", 226 | "options": { 227 | "raw": { 228 | "language": "json" 229 | } 230 | } 231 | }, 232 | "url": { 233 | "raw": "http://localhost:5000/api/v1/post/507f1f77bcf86cd7", 234 | "protocol": "http", 235 | "host": [ 236 | "localhost" 237 | ], 238 | "port": "5000", 239 | "path": [ 240 | "api", 241 | "v1", 242 | "post", 243 | "507f1f77bcf86cd7" 244 | ] 245 | } 246 | }, 247 | "response": [] 248 | }, 249 | { 250 | "name": "10. Delete Post - Success - api/v1/post/507f1f77bcf86cd799439011", 251 | "request": { 252 | "method": "DELETE", 253 | "header": [], 254 | "url": { 255 | "raw": "http://localhost:5000/api/v1/post/507f1f77bcf86cd799439011", 256 | "protocol": "http", 257 | "host": [ 258 | "localhost" 259 | ], 260 | "port": "5000", 261 | "path": [ 262 | "api", 263 | "v1", 264 | "post", 265 | "507f1f77bcf86cd799439011" 266 | ] 267 | } 268 | }, 269 | "response": [] 270 | }, 271 | { 272 | "name": "11. Delete Post - Failure - api/v1/post/507f1f77bcf86cd", 273 | "request": { 274 | "method": "DELETE", 275 | "header": [], 276 | "url": { 277 | "raw": "http://localhost:5000/api/v1/post/507f1f77bcf86cd", 278 | "protocol": "http", 279 | "host": [ 280 | "localhost" 281 | ], 282 | "port": "5000", 283 | "path": [ 284 | "api", 285 | "v1", 286 | "post", 287 | "507f1f77bcf86cd" 288 | ] 289 | } 290 | }, 291 | "response": [] 292 | } 293 | ] 294 | } --------------------------------------------------------------------------------