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 comprehensive NestJS package providing base classes, utilities, and decorators for building CRUD APIs with Prisma ORM integration, featuring pagination, search, filtering, and relation loading capabilities.
Installation
npm install nestjs-prisma-base
Features
- Prisma module with proper lifecycle management
- Base service with common CRUD operations
- Base controller with configurable REST endpoints
- Enhanced pagination with metadata - NEW in v0.5.0
- Limit protection and validation - NEW in v0.5.1
- Search and filtering capabilities - NEW in v0.6.0
- Advanced search with operators - NEW in v0.7.0
- Relation loading configuration - NEW in v0.8.0
- Configurable Base DTOs - NEW in v0.9.0
- Optional Swagger Integration - NEW in v0.9.0
- Minimal DTOs for maximum control - NEW in v0.9.0
- Base DTOs for standardizing request/response data
- Support for multiple Prisma clients/databases
- Factory functions to auto-generate components
Basic Usage
1. Set up the PrismaModule in your app
import { Module } from '@nestjs/common';
import { PrismaModule } from 'nestjs-prisma-base';
import { PrismaClient } from '@prisma/client';
@Module({
imports: [
// REQUIRED: Always provide a PrismaClient instance
PrismaModule.forRoot({
prismaClient: new PrismaClient(),
}),
// Other modules
],
})
export class AppModule {}
2. Create your entity 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;
}
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
// user.service.ts
import { Injectable } from '@nestjs/common';
import { BaseService, SearchConfig } from 'nestjs-prisma-base';
import { PrismaService } from 'nestjs-prisma-base';
import { User } from '@prisma/client';
import { CreateUserDto, UpdateUserDto } from './user.dto';
@Injectable()
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
protected readonly modelName = 'user'; // Prisma model name
// Configure search functionality
protected searchConfig: SearchConfig = {
defaultSearchFields: ['name', 'email'], // Fields to search by default
caseSensitive: false, // Case-insensitive search
searchMode: 'contains', // Search mode
maxSearchFields: 5, // Max fields allowed in search
};
constructor(protected readonly prisma: PrismaService) {
super(prisma);
}
}
4. Create your controller
// user.controller.ts
import { Controller } from '@nestjs/common';
import { BaseController, EnableEndpoint, EndpointType } from 'nestjs-prisma-base';
import { User } from '@prisma/client';
import { UserService } from './user.service';
import { CreateUserDto, UpdateUserDto } from './user.dto';
@Controller('users')
// IMPORTANT: By default, all endpoints are disabled for security
// You must explicitly enable each endpoint
@EnableEndpoint(EndpointType.FIND_ALL)
@EnableEndpoint(EndpointType.FIND_ONE)
@EnableEndpoint(EndpointType.CREATE)
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
constructor(private readonly userService: UserService) {
super(userService);
}
}
Enhanced Pagination (v0.5.0+)
The findAll
method now returns enhanced pagination metadata:
// GET /users?page=1&limit=10
{
"data": [
{ "id": 1, "name": "John", "email": "john@example.com" },
{ "id": 2, "name": "Jane", "email": "jane@example.com" }
],
"meta": {
"total": 150,
"page": 1,
"limit": 10,
"totalPages": 15,
"hasNext": true,
"hasPrev": false
}
}
Backward Compatibility
For projects that need the old array response, use findAllSimple()
:
// In your custom service
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
// Returns User[] instead of PaginationResult<User>
async getUsersAsArray(): Promise<User[]> {
return this.findAllSimple(1, 10);
}
}
Pagination Types
import { PaginationResult, PaginationMeta } from 'nestjs-prisma-base';
// Enhanced pagination response
interface PaginationResult<T> {
data: T[];
meta: PaginationMeta;
}
// Pagination metadata
interface PaginationMeta {
total: number; // Total number of records
page: number; // Current page number
limit: number; // Records per page
totalPages: number; // Total number of pages
hasNext: boolean; // Whether there's a next page
hasPrev: boolean; // Whether there's a previous page
}
Search and Filtering (v0.6.0+)
Powerful search and filtering capabilities with configurable options:
Basic Search Usage
// GET /users?search=john&page=1&limit=10
// Searches for "john" in default search fields (name, email)
// GET /users?search=john&searchFields=name,email
// Searches for "john" only in specified fields
// GET /users?sortBy=name&sortOrder=asc
// Sort results by name in ascending order
// GET /users?status=active&role=admin
// Filter by status=active AND role=admin
Search Configuration
Configure search behavior in your service:
import { Injectable } from '@nestjs/common';
import { BaseService, SearchConfig } from 'nestjs-prisma-base';
@Injectable()
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
protected readonly modelName = 'user';
// Configure search functionality
protected searchConfig: SearchConfig = {
defaultSearchFields: ['name', 'email'], // Fields to search by default
caseSensitive: false, // Case-insensitive search
searchMode: 'contains', // 'contains' | 'startsWith' | 'endsWith'
maxSearchFields: 5, // Maximum fields allowed in single search
};
constructor(protected readonly prisma: PrismaService) {
super(prisma);
}
}
Search Options
// In your service methods
import { BasicSearchOptions } from 'nestjs-prisma-base';
const searchOptions: BasicSearchOptions = {
search: 'john', // Search term
searchFields: ['name', 'email'], // Fields to search in
filters: {
// Exact match filters
status: 'active',
role: 'admin',
},
orderBy: {
// Sorting
name: 'asc',
createdAt: 'desc',
},
};
const results = await this.findAll(1, 20, searchOptions);
Search Modes
// Different search behaviors
protected searchConfig: SearchConfig = {
defaultSearchFields: ['name', 'email'],
// Contains (default) - matches anywhere in field
searchMode: 'contains', // "john" matches "johnsmith" and "ajohn"
// Starts with - matches beginning of field
searchMode: 'startsWith', // "john" matches "johnsmith" but not "ajohn"
// Ends with - matches end of field
searchMode: 'endsWith', // "john" matches "ajohn" but not "johnsmith"
};
Programmatic Search
// In your service
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
async searchActiveUsers(searchTerm: string): Promise<PaginationResult<User>> {
const searchOptions: BasicSearchOptions = {
search: searchTerm,
filters: { status: 'active' },
orderBy: { name: 'asc' },
};
return this.findAll(1, 20, searchOptions);
}
async findUsersByRole(role: string): Promise<User[]> {
const searchOptions: BasicSearchOptions = {
filters: { role },
orderBy: { name: 'asc' },
};
return this.findAllSimple(1, 100, searchOptions);
}
}
Advanced Query Examples
// Complex search with multiple filters
GET /users?search=john&searchFields=name&status=active&role=admin&sortBy=createdAt&sortOrder=desc
// Search in multiple fields with filters
GET /products?search=laptop&searchFields=name,description,sku&category=electronics&inStock=true
// Pagination with search
GET /orders?search=pending&status=pending&page=2&limit=25&sortBy=createdAt&sortOrder=desc
DTO Configuration & Swagger Integration (v0.9.0+)
Version 0.9.0 introduces flexible DTO configuration options and optional Swagger integration, giving you multiple approaches to define your DTOs based on your project needs.
DTO Options Overview
Choose the DTO approach that best fits your development style:
- Original DTOs:
BaseCreateDto
,BaseUpdateDto
,BaseResponseDto
- backward compatible - Configurable DTOs:
ConfigurableBaseCreateDto
, etc. - flexible configuration system - Swagger DTOs:
SwaggerBaseCreateDto
, etc. - automatic Swagger documentation - Minimal DTOs:
MinimalBaseCreateDto
, etc. - completely empty base classes
1. Configurable Base DTOs
Configurable DTOs allow you to control field inclusion and behavior globally or per-class:
import { ConfigurableBaseCreateDto, ConfigurableBaseUpdateDto, ConfigurableBaseResponseDto, configureDTOs } from 'nestjs-prisma-base';
// Global DTO configuration (applies to all configurable DTOs)
configureDTOs({
includeTimestamps: true,
includeId: true,
timestampFields: {
createdAt: 'created_at',
updatedAt: 'updated_at',
},
});
// Your DTOs extend configurable base classes
export class CreateUserDto extends ConfigurableBaseCreateDto {
@IsString()
name: string;
@IsEmail()
email: string;
}
export class UserResponseDto extends ConfigurableBaseResponseDto {
name: string;
email: string;
// id, createdAt, updatedAt automatically included based on config
}
// Per-class configuration (overrides global config)
UserResponseDto.configure({
includeTimestamps: false, // This class won't include timestamps
});
2. Swagger Integration
Automatically apply Swagger decorators when @nestjs/swagger
is available:
import { SwaggerBaseCreateDto, SwaggerBaseUpdateDto, SwaggerBaseResponseDto, configureSwaggerDTOs } from 'nestjs-prisma-base';
import { ApiProperty } from '@nestjs/swagger';
// Enable Swagger globally
configureSwaggerDTOs({
enabled: true,
includeExamples: true,
includeDescriptions: true,
fieldConfig: {
id: { description: 'User ID', example: 1 },
createdAt: { description: 'Creation time', example: '2023-01-01T00:00:00Z' },
},
});
export class CreateUserDto extends SwaggerBaseCreateDto {
@ApiProperty({ description: 'User name', example: 'John Doe' })
@IsString()
name: string;
@ApiProperty({ description: 'Email address', example: 'john@example.com' })
@IsEmail()
email: string;
}
export class UserResponseDto extends SwaggerBaseResponseDto {
@ApiProperty({ description: 'User name', example: 'John Doe' })
name: string;
@ApiProperty({ description: 'Email address', example: 'john@example.com' })
email: string;
// id, createdAt, updatedAt automatically get Swagger decorators
}
3. Minimal DTOs
For developers who want complete control with no additional fields:
import { MinimalBaseCreateDto, MinimalBaseUpdateDto, MinimalBaseResponseDto, MinimalBaseIdDto, MinimalBaseTimestampDto, MinimalBaseEntityDto } from 'nestjs-prisma-base';
// Completely empty base classes
export class CreateUserDto extends MinimalBaseCreateDto {
name: string;
email: string;
// Only your fields, nothing else
}
// Or use pre-built minimal variations
export class UserIdDto extends MinimalBaseIdDto {
// Contains: id?: number
}
export class UserTimestampsDto extends MinimalBaseTimestampDto {
// Contains: createdAt?: Date, updatedAt?: Date
}
export class UserEntityDto extends MinimalBaseEntityDto {
// Contains: id?: number, createdAt?: Date, updatedAt?: Date
name: string;
email: string;
}
4. PrismaModule DTO Configuration
Configure DTOs at the module level for automatic setup:
import { Module } from '@nestjs/common';
import { PrismaModule } from 'nestjs-prisma-base';
import { PrismaClient } from '@prisma/client';
@Module({
imports: [
PrismaModule.forRoot({
prismaClient: new PrismaClient(),
dtoOptions: {
// Global DTO configuration
dtoConfig: {
includeTimestamps: true,
includeId: true,
timestampFields: {
createdAt: 'createdAt',
updatedAt: 'updatedAt',
},
},
// Swagger integration configuration
swaggerIntegration: {
enabled: true,
includeExamples: true,
includeDescriptions: true,
includeTimestamps: true,
},
// Use minimal DTOs by default
useMinimalDTOs: false,
},
}),
],
})
export class AppModule {}
5. Advanced Configuration Examples
Custom Timestamp Fields
// Configure for databases with custom timestamp column names
configureDTOs({
includeTimestamps: true,
timestampFields: {
createdAt: 'created_at', // Maps to created_at column
updatedAt: 'modified_at', // Maps to modified_at column
},
});
Per-Service Configuration
// Different DTO configs for different services
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
constructor(prisma: PrismaService) {
super(prisma);
// Configure DTOs specifically for this service
CreateUserDto.configure({ includeTimestamps: false });
UserResponseDto.configure({ includeId: true, includeTimestamps: true });
}
}
Conditional Swagger Setup
// Only enable Swagger in development/staging
configureSwaggerDTOs({
enabled: process.env.NODE_ENV !== 'production',
includeExamples: true,
includeDescriptions: process.env.NODE_ENV === 'development',
});
Manual Swagger Decorator Application
import { applySwaggerDecoratorsToClass } from 'nestjs-prisma-base';
// Manually apply Swagger decorators to any class
applySwaggerDecoratorsToClass(MyCustomDto, [
{
propertyKey: 'name',
options: { description: 'Name field', example: 'John' },
},
{
propertyKey: 'email',
options: { description: 'Email field', example: 'john@example.com' },
},
]);
6. Migration from Existing DTOs
Migrating to configurable DTOs is completely optional and non-breaking:
// Before (v0.8.x and earlier) - still works!
export class CreateUserDto extends BaseCreateDto {
name: string;
email: string;
}
// After (v0.9.0+) - optional upgrade
export class CreateUserDto extends ConfigurableBaseCreateDto {
name: string;
email: string;
}
// Or with Swagger support
export class CreateUserDto extends SwaggerBaseCreateDto {
@ApiProperty({ description: 'User name' })
name: string;
@ApiProperty({ description: 'Email address' })
email: string;
}
7. Configuration Utilities
Check current configuration and Swagger availability:
import { getDTOConfig, getSwaggerDTOConfig, isSwaggerIntegrationEnabled } from 'nestjs-prisma-base';
// Check current DTO configuration
const dtoConfig = getDTOConfig();
console.log('Timestamps enabled:', dtoConfig.includeTimestamps);
// Check Swagger configuration
const swaggerConfig = getSwaggerDTOConfig();
console.log('Swagger enabled:', swaggerConfig.enabled);
// Check if Swagger is available and enabled
if (isSwaggerIntegrationEnabled()) {
console.log('Swagger decorators will be applied');
}
Configuration Interface Reference
interface DTOConfig {
includeTimestamps?: boolean; // Include createdAt/updatedAt fields
includeId?: boolean; // Include id field in response DTOs
swaggerEnabled?: boolean; // Enable Swagger integration
timestampFields?: {
// Custom timestamp field names
createdAt?: string;
updatedAt?: string;
};
}
interface SwaggerDTOConfig {
enabled: boolean; // Enable/disable Swagger decorators
includeTimestamps?: boolean; // Include timestamps in Swagger docs
includeExamples?: boolean; // Include examples in Swagger docs
includeDescriptions?: boolean; // Include descriptions in Swagger docs
fieldConfig?: {
// Custom field configurations
id?: { description?: string; example?: any };
createdAt?: { description?: string; example?: any };
updatedAt?: { description?: string; example?: any };
};
}
Limit Protection (v0.5.1+)
Protect your application from performance issues by configuring pagination limits:
Default Configuration
By default, the base service uses these safe limits:
{
defaultLimit: 10, // Default records per page
maxLimit: 100, // Maximum allowed limit
allowUnlimited: false // Disable unlimited results
}
Custom Configuration
Override pagination configuration in your service:
import { Injectable } from '@nestjs/common';
import { BaseService, PaginationConfig } from 'nestjs-prisma-base';
@Injectable()
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
protected readonly modelName = 'user';
// Custom pagination limits
protected paginationConfig: PaginationConfig = {
defaultLimit: 20, // Default 20 items per page
maxLimit: 200, // Maximum 200 items per page
allowUnlimited: false, // Don't allow unlimited results
};
constructor(protected readonly prisma: PrismaService) {
super(prisma);
}
}
Validation Examples
The service automatically validates pagination parameters:
// ✅ Valid requests
GET /users?page=1&limit=10
GET /users?page=2&limit=50
GET /users?page=1 // Uses default limit (20)
// ❌ Invalid requests (throw BadRequestException)
GET /users?page=0&limit=10 // Page must be >= 1
GET /users?page=1&limit=0 // Limit must be >= 1 (unless unlimited allowed)
GET /users?page=1&limit=300 // Exceeds maxLimit (200)
GET /users?page=1&limit=-1 // Unlimited not allowed by default
Allowing Unlimited Results
For administrative or export operations, you can allow unlimited results:
export class AdminService extends BaseService<any, any, any> {
protected paginationConfig: PaginationConfig = {
defaultLimit: 50,
maxLimit: 1000,
allowUnlimited: true, // ⚠️ Use carefully!
};
async exportAllData(): Promise<any[]> {
// Pass -1 or 0 for unlimited results
return this.findAllSimple(1, -1);
}
}
⚠️ Warning: Unlimited results can severely impact performance and memory usage. Only enable for trusted administrative operations.
Multiple Database Support
When working with multiple databases:
import { Module, Inject } from '@nestjs/common';
import { PrismaModule, PrismaService } from 'nestjs-prisma-base';
import { PrismaClient as UsersDbClient } from './prisma/generated/users-client';
import { PrismaClient as ProductsDbClient } from './prisma/generated/products-client';
@Module({
imports: [
// First database
PrismaModule.forRoot({
prismaClient: new UsersDbClient({
datasources: { db: { url: process.env.USERS_DATABASE_URL } },
}),
providerToken: 'USERS_PRISMA_SERVICE',
}),
// Second database
PrismaModule.forRoot({
prismaClient: new ProductsDbClient({
datasources: { db: { url: process.env.PRODUCTS_DATABASE_URL } },
}),
providerToken: 'PRODUCTS_PRISMA_SERVICE',
isGlobal: false,
}),
],
})
export class AppModule {}
// Services for different databases
@Injectable()
export class UserService extends BaseService<User, CreateUserDto, UpdateUserDto> {
protected readonly modelName = 'user';
constructor(@Inject('USERS_PRISMA_SERVICE') prisma: PrismaService) {
super(prisma);
}
}
@Injectable()
export class ProductService extends BaseService<Product, CreateProductDto, UpdateProductDto> {
protected readonly modelName = 'product';
constructor(@Inject('PRODUCTS_PRISMA_SERVICE') prisma: PrismaService) {
super(prisma);
}
}
Alternative: Using forFeature
For a cleaner organization:
// Even cleaner approach for multiple databases
@Module({
imports: [
PrismaModule.forFeature({
name: 'users', // Creates USERS_PRISMA_SERVICE token
prismaClient: new UsersDbClient({
datasources: { db: { url: process.env.USERS_DATABASE_URL } },
}),
}),
PrismaModule.forFeature({
name: 'products', // Creates PRODUCTS_PRISMA_SERVICE token
prismaClient: new ProductsDbClient({
datasources: { db: { url: process.env.PRODUCTS_DATABASE_URL } },
}),
}),
],
})
export class AppModule {}
Using Factory Functions
Generate an entire module with one function call:
import { createModelModule, EndpointType } from 'nestjs-prisma-base';
// Create a module with specific enabled endpoints
export const UserModule = createModelModule({
modelName: 'user',
routePath: 'users',
enabledEndpoints: [EndpointType.FIND_ALL, EndpointType.FIND_ONE, EndpointType.CREATE],
});
// Create a module with all endpoints enabled
export const ProductModule = createModelModule({
modelName: 'product',
enableAllEndpoints: true,
});
Endpoint Configuration
Available endpoints that can be enabled:
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
}
Enabling All Endpoints
@Controller('users')
@EnableAllEndpoints()
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
// ...
}
Disabling Specific Endpoints
@Controller('users')
@EnableAllEndpoints()
@DisableEndpoint(EndpointType.REMOVE)
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
// ...
}
License
MIT