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

@sabinthedev/nestjs-prisma

v1.0.57

Published

A NestJS module that allows you use Prisma, set up multiple Prisma services, and use multi-tenancy in each Prisma service.

Downloads

4

Readme

NestJS Prisma Module

Header

Tests Linting

Installation

To use this package, first install it:

npm i @sabinthedev/nestjs-prisma

Or

pnpm add @sabinthedev/nestjs-prisma

Basic Usage

In order to use this package, you will need one or more Prisma Clients set up in your project.

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PrismaClient } from '@prisma/client';
import { PrismaModule } from '@sabinthedev/nestjs-prisma';

@Module({
  imports: [
    PrismaModule.register({
      client: PrismaClient,
      name: 'PRISMA',
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

There are also various options you may pass to the register function to customize how Prisma Client is instantiated and how to handle connections and requests.

Multitenancy

This plugin allows you to handle multi-tenant applications by abstracting a service layer above Prisma Client to cache Prisma Client instances in-memory and select the appropriate tenant connection on each request.

Below is an example of how to configure PrismaModule to handle multiple tenants:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PrismaClient } from '@prisma/client';
import { PrismaModule } from '@sabinthedev/nestjs-prisma';

@Module({
  imports: [
    PrismaModule.register({
      client: PrismaClient,
      name: 'PRISMA',
      multitenancy: true,
      datasource: 'postgresql://johndoe:randompassword@localhost:5432/mydb',
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

When configuring multi-tenancy, the datasource key is required as it is used as the base URL on which the tenant database is added.

To access a specific tenant database, add a header to your HTTP request named x-tenant-id whose value is the name of the tenant DB you wish to access. PrismaModule will generate a new instance of Prisma Client using the base URL you provided along with the specification for the tenant database.

Example Request

In the scenario below, your server is at localhost:3000 and has an endpoint /users. The client accessing the resource requesting data from a tenant database named tenant-name.

curl -XGET -H 'x-tenant-id: tenant-name' 'localhost:3000/users'

Supported Database Providers

Note: SQLite (or any database servers that do not support multiple databases) is not supported.

The list of supported database providers for this feature are as follows:

  • PostgreSQL
  • MySQL
  • SQL Server
  • MongoDB

More to be added soon...

API

register(options)

The register function registers PrismaModule and allows you to pass in options that change the behavior of the module and the generated Prisma Client instances. This function takes in a single parameter, options. This is an object with the following available keys:

| Parameter | Type | | Description | | ------------ | --------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | name | string | Required | The dependency injection token to use with @Inject. See the docs for more info. | | global | Optional | false | When true, the module is marked as a @Global() module. | | logging | boolean | Optional | Enables logging within the module using NestJS's Logger module. | | client | PrismaClient class or ClientConfig | Required | The PrismaClient class to be instantiated, or an object containing a reference to a PrismaClient class and a callback function that allows you to modify the instantiated class on a per-tenant basis. | | multitenancy | boolean | Optional* | A flag that turns on the multi-tenancy capabilities of this module. | | datasource | string | Optional* | A datasource URL that is used to manually override Prisma Client's datasource. This is used as the base URL when dynamically selecting tenant databases. | | requestType | HTTP or GRPC | Optional* | Defines what kind of request to handle, allowing the plugin to correctly grab a tenant ID. (Defaults to HTTP). More to be added. |

Note: If multitenancy OR datasources are present, both are required. The built-in type-safety will make this apparent.

ClientConfig

An object of the ClientConfig type is able to be provided instead of a PrismaClient class to the client option key. This object should contain:

| Parameter | Type | | Description | | ----------- | ------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ | | client | PrismaClient | Required | A PrismaClient class | | initializer | Initializer | Required | A function that is called when a PrismaClient is instantiated. | | options | PrismaClient constructor args | Optional | See the Prisma Client API reference |

initializer(client: PrismaClient, tenant: string) => PrismaClient

This function gives you access to the generated client and the associated tenant name (if any) so you can customize the client instance with functions such as $on, $use and more. The available client methods can be found here.

Within this function, you can provide any function you would like to run when a Prisma Client is instantiated.

The return of this function must be the Prisma Client.

Advanced Usage

In the scenario below, the module is configured to:

  • Use multi-tenancy
  • Log info on the connection handling
  • Initialize PrismaClient with logging enabled at the info level (see Prisma's docs on logging)
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PrismaClient } from '@prisma/client';
import { PrismaModule } from '@sabinthedev/nestjs-prisma';

@Module({
  imports: [
    PrismaModule.register({
      client: {
        class: PrismaMock,
        options: {
          log: [
            {
              emit: 'event',
              level: 'info',
            },
          ],
        },
      },
      logging: true,
      multitenancy: true,
      datasource: 'file:./dev.db',
      name: 'PRISMA',
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Multiple Prisma Modules

You may register this module multiple times within your application to provide access to different databases.

Configure a new Prisma schema. Make sure to specify a custom output in the client generator if your first client used the default location. This ensures the newly generated client does not override the one at node_modules/@prisma/client.

You can then register a second client in a way similar to the following:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PrismaModule } from '@sabinthedev/nestjs-prisma';

// Import your clients
import { PrismaClient as AuthClient } from '../prisma-clients/auth';
import { PrismaClient as UsersClient } from '../prisma-clients/users';

@Module({
  imports: [
    // Register the module once for each client
    PrismaModule.register({
      client: AuthClient,
      name: 'AUTH',
    }),
    PrismaModule.register({
      client: UsersClient,
      name: 'USERS',
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

In the above scenario, you may be working in a microservice architecture who's Authentication service uses a separate database than the Users service. The configuration above registers both clients as separate providers.

You, of course, have all of the granular control and options as before when registering multiple modules.

Guides

Using Custom Logger and Grafana Loki

This module makes use of the built-in NestJS Logger module. Let's say your app uses a Pino logger and aggregrates your logs into Grafana Loki, how would you do that?

First, you'll want the pino-nestjs and pino-loki packages:

pnpm add pino-nestjs pino-http pino-loki

Then configure a custom logger module:

// modules/logger.module.ts
import { Module } from '@nestjs/common';
import { LoggerModule as PinoLoggerModule } from 'nestjs-pino';

@Module({
  imports: [
    PinoLoggerModule.forRoot({
      pinoHttp: {
        transport: {
          target: 'pino-loki',
          options: {
            batching: true,
            interval: 5,
            host: process.env.LOKI_URL,
            basicAuth: {
              username: process.env.LOKI_USERNAME,
              password: process.env.LOKI_PASSWORD,
            },
          },
        },
      },
    }),
  ],
})
export class LoggerModule {}

Above we set up a Pino logger configured to use Pino's pinoHttp transport option to send logs to Loki.

Next we need to import this into our app module:

// src/app.module.ts
import { Module } from '@nestjs/common';
import { LoggerModule } from '@/modules/logger.module';

@Module({
  imports: [LoggerModule],
})
export class AppModule {}

This provides the module to the application at the root level.

Lastly, in main.ts you will want to set this logger as the default logger so you can continue to use @nestjs/common's Logger module:

// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Logger } from 'nestjs-pino';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, { rawBody: true });
  app.useLogger(app.get(Logger));
  await app.listen(3000);
}
bootstrap();

With that configured, the @nestjs/common library will now use the Pino logger with the Loki transport under the hood, meaning all of the logs from the this library will go to Loki (if logging is turned on).

Author

I'm Sabin Adams! Find me on 𝕏

Contributors

None yet! But contributions are welcome!

License

Licensed under MIT.