npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@golevelup/nestjs-hasura

v3.0.6

Published

Badass utilities for integrating Hasura and NestJS

Downloads

4,153

Readme

@golevelup/nestjs-hasura

Leverage NestJS to make incorporating business logic and event processing easier with Hasura. 🚀

Features

  • 🎉 Exposes an API endpoint from your NestJS application at to be used for event processing from Hasura. Defaults to /hasura/events/ but can be easily configured

  • 🔒 Automatically validates that the event payload was actually sent from Hasura using configurable secrets

  • 🕵️ Discovers methods from your application and automatically turns them into Hasura event handlers. Supports insert, update and delete events from your tables as well as scheduled events based on a CRON schedule

  • 🧭 Routes incoming webhook payloads to the correct event handler based on configuration so you can maintain a single webhook endpoint for Hasura

  • 🔌 Optionally supports automatic management of your Hasura metadata files which means that your application code can be the source of truth for configuration of events. This reduces a ton of boilerplate and developer overhead

Usage

Install

npm install ---save @golevelup/nestjs-hasura

or

yarn add @golevelup/nestjs-hasura

Import

Import and add HasuraModule to the imports section of the consuming module (most likely AppModule). In order to ensure that your Hasura events webhook endpoint is secure, the module requires configuration for an HTTP header name and value that will be used to verify that the event actually came from Hasura.

Configuration

The Hasura Module supports both the forRoot and forRootAsync patterns for configuration, so you can easily retrieve the necessary config values from a ConfigService or other provider.

Usage

Integrating with your NestJS app

The HasuraModule makes it easy to reuse the same events API endpoint for all events that you create in Hasura. The internal routing mechanism on the NestJS side ensures that the all events coming in through the endpoint will be sent to the correct handler. The endpoint provided defaults to /hasura/events. This can be overriden with the module by specifying an alternative controllerPrefix so for example you could set this to webhooks and the resulting endpoint would be available at /webhooks/events.

Automatically Synchronize Hasura Metadata

One of the more powerful features of this Module is the ability to automatically generate the necessary Hasura metadata for your event handlers instead of having to worry about configuring each handler individually. Under the hood, this uses the @hasura/metadata to generate and merge changes to your tables.yaml and cron_triggers.yaml files.

If you decide to opt into this functionality, you should include the optional managedMetaDataConfig object when importing the HasuraModule into your application.

import { HasuraModule } from '@golevelup/nestjs-hasura';

@Module({
  imports: [
    HasuraModule.forRoot(HasuraModule, {
      webhookConfig: {
        secretFactory: secret,
        secretHeader: secretHeader,
      },
      managedMetaDataConfig: {
        dirPath: join(process.cwd(), 'hasura/metadata'),
        secretHeaderEnvName: 'HASURA_NESTJS_WEBHOOK_SECRET_HEADER_VALUE',
        nestEndpointEnvName: 'NESTJS_EVENT_WEBHOOK_ENDPOINT',
        defaultEventRetryConfig: {
          intervalInSeconds: 15,
          numRetries: 3,
          timeoutInSeconds: 100,
          toleranceSeconds: 21600,
        },
      },
    }),
  ],
})
export class AppModule {
  // ...
}

It is recommended that you conditionally add this configuration based on the Node Environment as this should only be used in development environments to track the necessary changes to your metadata yaml files so that they can be tracked in source control.

After generating changes to these files you should make sure they are applied against your Hasura instance using the CLI command:

hasura metadata apply

Opting Out

If you decide to opt out of automatic metadata synchronization it is up to you to ensure that the secret header name and values match. When creating the event in the Hasura console, you should set these values such that they match the configuration provided to the HasuraModule configuration in your NestJS application. This ensures that only Hasura can trigger events in your system.

Registering Table Event Handlers

Decorate methods in your NestJS providers in order to have them be automatically attached as event handlers for incoming Hasura events. The event payload will be analyzed and routed to your provider methods based on the configuration provided in the decorator.

import {
  TrackedHasuraEventHandler,
  HasuraUpdateEvent,
  HasuraInsertEvent,
} from '@golevelup/nestjs-hasura';

@Injectable()
class UsersService {
  @TrackedHasuraEventHandler({
    triggerName: 'user-created',
    tableName: 'user',
    definition: { type: 'insert' },
  })
  handleUserCreated(evt: HasuraInsertEvent<User>) {}

  @TrackedHasuraEventHandler({
    triggerName: 'user-updated',
    tableName: 'user',
    definition: { type: 'update', columns: ['avatarUrl'] },
  })
  handleUserUpdated(evt: HasuraUpdateEvent<User>) {}
}

Registering Scheduled Event Handlers

import { TrackedHasuraScheduledEventHandler } from '@golevelup/nestjs-hasura';

@Injectable()
class RecurringJobService {
  @TrackedHasuraScheduledEventHandler({
    cronSchedule: CommonCronSchedules.EveryMinute,
    name: 'every-minute',
    payload: {},
    comment: 'this is my comment',
  })
  public async cronTask(evt: any) {
    this.logger.log(evt);
  }
}

Retry Configuration

Retry configuration for both Table Event handlers as well as Scheduled Event handlers can be configured on the individual decorator or you can provide a default retry configuration at the module level that will be used for any event handler that does not explicitly provide its own retry settings.

Configuring Hasura Environment Variables

You should provide ENV variables to your Hasura instance that map the webhook endpoint and secret header values for communication to your NestJS application.

In the examples above, HASURA_NESTJS_WEBHOOK_SECRET_HEADER_VALUE and NESTJS_EVENT_WEBHOOK_ENDPOINT were used. The webhook endpoint should point to the automatically scaffolded events endpoint eg: https://my-nest-app.com/api/hasura/events

Usage with Interceptors, Guards and Filters

This library is built using an underlying NestJS concept called External Contexts which allows for methods to be included in the NestJS lifecycle. This means that Guards, Interceptors and Filters (collectively known as "enhancers") can be used in conjunction with Hasura event handlers. However, this can have unwanted/unintended consequences if you are using Global enhancers in your application as these will also apply to all Hasura event handlers. If you were previously expecting all contexts to be regular HTTP contexts, you may need to add conditional logic to prevent your enhancers from applying to Hasura event handlers.

You can identify Hasura event contexts by their context type, 'hasura_event':

@Injectable()
class ExampleInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler<any>) {
    const contextType = context.getType<'http' | 'hasura_event'>();

    // Do nothing if this is a Hasura event
    if (contextType === 'hasura_event') {
      return next.handle();
    }

    // Execute custom interceptor logic for HTTP request/response
    return next.handle();
  }
}

Related Hasura Documentation

Concepts

https://hasura.io/docs/1.0/graphql/manual/event-triggers/index.html#event-triggers

Tutorials

https://hasura.io/docs/1.0/graphql/manual/getting-started/first-event-trigger.html https://hasura.io/event-triggers

Contribute

Contributions welcome! Read the contribution guidelines first.

License

MIT License