JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 126
  • Score
    100M100P100Q88069F
  • License MIT

A reusable NestJS module for Prisma ORM with base classes for controller, service and DTOs

Package Exports

  • nestjs-prisma-base
  • nestjs-prisma-base/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (nestjs-prisma-base) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

NestJS Prisma Base

A reusable NestJS module for Prisma ORM with base classes for controllers, services, and DTOs.

Installation

npm install nestjs-prisma-base

Features

  • Ready-to-use Prisma module with proper lifecycle management
  • Base service with common CRUD operations
  • Base controller with configurable REST endpoints
  • Base DTOs for standardizing request/response data
  • Utility decorators for easier implementation
  • Factory functions to auto-generate components from Prisma models
  • Selective endpoint activation for precise API control

Usage

Option 1: Extending Base Classes (Manual Approach)

1. Import the PrismaModule in your app module

import { Module } from '@nestjs/common';
import { PrismaModule } from 'nestjs-prisma-base';

@Module({
  imports: [
    PrismaModule.forRoot(),
    // Your other modules
  ],
})
export class AppModule {}

Using Multiple Prisma Clients

When working with multiple databases that have different schemas, each schema requires its own Prisma client. This package supports using multiple clients in the same application.

import { Module } from '@nestjs/common';
import { PrismaModule } from 'nestjs-prisma-base';
import { PrismaClient as UsersDbClient } from './prisma/generated/users-client';
import { PrismaClient as ProductsDbClient } from './prisma/generated/products-client';

@Module({
  imports: [
    // Register the Users database client
    PrismaModule.forRoot({
      prismaClient: new UsersDbClient({
        datasources: {
          db: { url: process.env.USERS_DATABASE_URL },
        },
      }),
      providerToken: 'USERS_PRISMA_SERVICE',
      isGlobal: true, // Set as the default service for the app
    }),

    // Register the Products database client
    PrismaModule.forRoot({
      prismaClient: new ProductsDbClient({
        datasources: {
          db: { url: process.env.PRODUCTS_DATABASE_URL },
        },
      }),
      providerToken: 'PRODUCTS_PRISMA_SERVICE',
      isGlobal: false, // Don't register globally to avoid conflicts
    }),

    // Feature modules
    UsersModule,
    ProductsModule,
  ],
})
export class AppModule {}

Then inject the correct service in your feature modules:

// Users database service
@Injectable()
@ModelName('user')
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
  constructor(@Inject('USERS_PRISMA_SERVICE') prisma: PrismaService) {
    super(prisma);
  }
}

// Products database service
@Injectable()
@ModelName('product')
export class ProductService extends BaseService<Product, CreateProductDto, UpdateProductDto> {
  constructor(@Inject('PRODUCTS_PRISMA_SERVICE') prisma: PrismaService) {
    super(prisma);
  }
}

Alternative: Create Feature-Specific Modules

For better organization, you can create separate modules for each database:

// users-db.module.ts
@Module({
  providers: [
    {
      provide: 'USERS_PRISMA_SERVICE',
      useFactory: () => {
        return new PrismaService(
          new UsersDbClient({
            datasources: {
              db: { url: process.env.USERS_DATABASE_URL },
            },
          })
        );
      },
    },
  ],
  exports: ['USERS_PRISMA_SERVICE'],
})
export class UsersDbModule {}

// products-db.module.ts
@Module({
  imports: [
    PrismaModule.forRoot({
      prismaClient: new ProductsDbClient({
        datasources: {
          db: { url: process.env.PRODUCTS_DATABASE_URL },
        },
      }),
      providerToken: 'PRODUCTS_PRISMA_SERVICE',
      isGlobal: false,
    }),
  ],
  exports: ['PRODUCTS_PRISMA_SERVICE'],
})
export class ProductsDbModule {}

Then import these modules in your feature modules:

@Module({
  imports: [UsersDbModule],
  controllers: [UserController],
  providers: [UserService],
})
export class UsersModule {}

2. Create your entity DTOs by extending the base DTOs

// user.dto.ts
import { BaseCreateDto, BaseUpdateDto, BaseResponseDto } from 'nestjs-prisma-base';
import { IsEmail, IsString, IsOptional } from 'class-validator';

export class CreateUserDto extends BaseCreateDto {
  @IsString()
  name: string;

  @IsEmail()
  email: string;

  @IsString()
  password: string;
}

export class UpdateUserDto extends BaseUpdateDto {
  @IsString()
  @IsOptional()
  name?: string;

  @IsEmail()
  @IsOptional()
  email?: string;
}

export class UserResponseDto extends BaseResponseDto {
  name: string;
  email: string;
}

3. Create your service by extending the base service

// user.service.ts
import { Injectable } from '@nestjs/common';
import { BaseService, ModelName, PrismaService } from 'nestjs-prisma-base';
import { User } from '@prisma/client';
import { CreateUserDto, UpdateUserDto } from './user.dto';

@Injectable()
@ModelName('user')
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
  constructor(prisma: PrismaService) {
    super(prisma);
  }

  // Add custom methods here
}

4. Create your controller by extending the base controller with endpoint configuration

// user.controller.ts
import { Controller } from '@nestjs/common';
import { BaseController, EnableEndpoint, EndpointType, EnableAllEndpoints, DisableEndpoint } from 'nestjs-prisma-base';
import { User } from '@prisma/client';
import { UserService } from './user.service';
import { CreateUserDto, UpdateUserDto } from './user.dto';

@Controller('users')
// Option 1: Enable specific endpoints
@EnableEndpoint(EndpointType.FIND_ALL)
@EnableEndpoint(EndpointType.FIND_ONE)
@EnableEndpoint(EndpointType.CREATE)

// Option 2: Enable all endpoints at once
// @EnableAllEndpoints()

// Option 3: Enable all except specific ones
// @EnableAllEndpoints()
// @DisableEndpoint(EndpointType.REMOVE)
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
  constructor(private readonly userService: UserService) {
    super(userService);
  }

  // Add custom endpoints here
  // Don't forget to enable your custom endpoints!
  @EnableEndpoint('findByEmail')
  @Get('by-email/:email')
  findByEmail(@Param('email') email: string) {
    return this.userService.findByEmail(email);
  }
}

Option 2: Using Factory Functions (Auto-Generated Approach)

1. Generate an entire module for a model with configurable endpoints

// user.module.ts
import { createModelModule, EndpointType } from 'nestjs-prisma-base';

// Option 1: Create module with specific enabled endpoints
export const UserModule = createModelModule({
  modelName: 'user',
  routePath: 'users',
  enabledEndpoints: [EndpointType.FIND_ALL, EndpointType.FIND_ONE, EndpointType.CREATE],
});

// Option 2: Create module with all endpoints enabled
export const ProductModule = createModelModule({
  modelName: 'product',
  enableAllEndpoints: true,
});

// Option 3: Create module with custom service
export const CategoryModule = createModelModule({
  modelName: 'category',
  enableAllEndpoints: true,
  serviceType: CategoryService, // Your custom service class
  providers: [
    /* Additional providers */
  ],
  imports: [
    /* Additional imports */
  ],
  exports: [
    /* Additional exports */
  ],
});

2. Import the generated module in your app module

// app.module.ts
import { Module } from '@nestjs/common';
import { PrismaModule } from 'nestjs-prisma-base';
import { UserModule } from './user.module';

@Module({
  imports: [
    PrismaModule.forRoot(),
    UserModule,
    // Other modules
  ],
})
export class AppModule {}

Endpoint Configuration

Important: By default, all endpoints are disabled for security reasons. In version 0.2.0 and above, you must explicitly enable each endpoint you want to expose. This provides better security and control over your API surface.

Available Endpoint Types

export enum EndpointType {
  FIND_ALL = 'findAll', // GET /resource
  FIND_ONE = 'findOne', // GET /resource/:id
  CREATE = 'create', // POST /resource
  UPDATE = 'update', // PATCH /resource/:id
  REMOVE = 'remove', // DELETE /resource/:id
}

Swagger Integration

When using this package with Swagger documentation, endpoints that are disabled will be automatically hidden from the Swagger UI. This is accomplished through the ApiExcludeDisabledEndpoint decorator that's applied to all standard endpoints in the BaseController.

If you're creating custom endpoints, you can use the decorator to hide them from Swagger when they're disabled:

@Get('custom-endpoint')
@ApiExcludeDisabledEndpoint('customEndpoint')
customEndpoint() {
  if (!this.isEndpointEnabled('customEndpoint')) {
    throw new NotFoundException('Endpoint not available');
  }
  // Your implementation
}

This requires the @nestjs/swagger package to be installed in your project.

Enabling Endpoints with Decorators

You can enable endpoints at the controller level:

@Controller('users')
@EnableEndpoint(EndpointType.FIND_ALL)
@EnableEndpoint(EndpointType.FIND_ONE)
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
  // ...
}

Or enable all endpoints at once:

@Controller('users')
@EnableAllEndpoints()
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
  // ...
}

Disabling Specific Endpoints

You can disable specific endpoints even when using @EnableAllEndpoints():

@Controller('users')
@EnableAllEndpoints()
@DisableEndpoint(EndpointType.REMOVE)
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
  // ...
}

Enabling Method-Level Endpoints

You can also selectively enable endpoints at the method level:

@Controller('users')
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
  // Only this method will be available
  @EnableEndpoint('findAdmins')
  @Get('admins')
  findAdmins() {
    return this.userService.findAdmins();
  }
}

License

MIT

Simplified: Using forFeature for Multiple Databases

For an even cleaner approach, use the forFeature method to register databases:

import { Module } from '@nestjs/common';
import { PrismaModule } from 'nestjs-prisma-base';
import { PrismaClient as UsersDbClient } from './prisma/generated/users-client';
import { PrismaClient as ProductsDbClient } from './prisma/generated/products-client';

@Module({
  imports: [
    // Register both database clients
    PrismaModule.forFeature({
      name: 'users',
      prismaClient: new UsersDbClient({
        datasources: {
          db: { url: process.env.USERS_DATABASE_URL },
        },
      }),
    }),

    PrismaModule.forFeature({
      name: 'products',
      prismaClient: new ProductsDbClient({
        datasources: {
          db: { url: process.env.PRODUCTS_DATABASE_URL },
        },
      }),
    }),

    // Feature modules
    UsersModule,
    ProductsModule,
  ],
})
export class AppModule {}

Then inject them in your services:

@Injectable()
@ModelName('user')
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
  constructor(@Inject('USERS_PRISMA_SERVICE') prisma: PrismaService) {
    super(prisma);
  }
}