Webhooks are a popular approach for enabling real-time notifications and updates between applications. They provide an efficient way to communicate with external systems and automate workflows. In this blog post, we'll explore how to develop a webhook system using NestJS, to enable event-based integrations with external systems.
Setting up a NestJS Application
First, let's start by installing the NestJS CLI globally (if you do not have it already) to initialize and set up NestJS applications:
npm i -g @nestjs/cli
nest new webhook-app
This command will create a simple web API that exposes a single endpoint at the root address (localhost:3000/). For our example, we will create an endpoint to simulate order creation and notify an external shipping application to pick up the product. We will work on app.service.ts
to send the request to our root application:
// app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
createOrder(data) {
// we omit the implementation of order creation
return data;
}
}
Now, let's import the WebhookService
into our AppController
and call the notifyShippingApplication
method when a new order is created:
// app.controller.ts
import { Body, Controller, Post } from '@nestjs/common';
import { AppService } from './app.service';
import { WebhookService } from './webhook.service';
@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
private readonly webhookService: WebhookService,
) {}
@Post('/order')
async createOrder(@Body() data) {
const createdOrder = this.appService.createOrder(data);
// Notify the shipping application using the webhook
await this.webhookService.notifyShippingApplication(createdOrder);
return createdOrder;
}
}
Testing the Webhook System
Finally, let's test that the webhook is called correctly when creating a new order. You can use a tool like Postman to make the request to our "localhost:3000/order" endpoint:
POST /a13b5452-5f37-485b-be82-92b84a1c30ab HTTP/1.1
Host: webhook.site
Content-Type: application/json
Content-Length: 85
{
"productId": 1,
"amount": 1,
"deliveryAddress": "Fake Street 123"
}
Now, open webhook.site in a browser tab and verify that a request was received with the data that we sent to our webhook. If the webhook.site were the shipping app, it would already have been notified to pick up our product at the address we sent.
![](https://utopia-insights.dev/content/images/2023/06/Screenshot-2023-06-10-at-8.41.41-PM.png)
Using an Interceptor to automate the webhook notification
To implement this, first create a new interceptor called WebhookInterceptor
:
// webhook.interceptor.ts
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { WebhookService } from './webhook.service';
@Injectable()
export class WebhookInterceptor implements NestInterceptor {
constructor(private readonly webhookService: WebhookService) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
tap(async (createdOrder) => {
await this.webhookService.notifyShippingApplication(createdOrder);
}),
);
}
}
Now, you need to bind the WebhookInterceptor
to the createOrder
method in the AppController
. You can do this by using the @UseInterceptors()
decorator:
// app.controller.ts
import { Body, Controller, Post, UseInterceptors } from '@nestjs/common';
import { AppService } from './app.service';
import { WebhookInterceptor } from './webhook.interceptor';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Post('/order')
@UseInterceptors(WebhookInterceptor)
createOrder(@Body() data) {
const createdOrder = this.appService.createOrder(data);
return createdOrder;
}
}
And that's it!!! With this implementation, the WebhookInterceptor
will automatically call the notifyShippingApplication
method after the createOrder
method is executed, without the need to explicitly call it in the createOrder
method itself.
This approach allows you to keep the webhook notification logic separate from the main route handler, making your code more modular and maintainable.
you can find the full source code on Github.