nestjs-prisma-base
Version:
A reusable NestJS module for Prisma ORM with base classes for controller, service and DTOs
277 lines (217 loc) • 7.43 kB
Markdown
# NestJS Prisma Base
A reusable NestJS module for Prisma ORM with base classes for controllers, services, and DTOs.
## Installation
```bash
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
```typescript
import { Module } from '@nestjs/common';
import { PrismaModule } from 'nestjs-prisma-base';
@Module({
imports: [
PrismaModule.forRoot(),
// Your other modules
],
})
export class AppModule {}
```
#### 2. Create your entity DTOs by extending the base DTOs
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
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:
```typescript
@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:
```typescript
@Controller('users')
@EnableEndpoint(EndpointType.FIND_ALL)
@EnableEndpoint(EndpointType.FIND_ONE)
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
// ...
}
```
Or enable all endpoints at once:
```typescript
@Controller('users')
@EnableAllEndpoints()
export class UserController extends BaseController<User, CreateUserDto, UpdateUserDto> {
// ...
}
```
### Disabling Specific Endpoints
You can disable specific endpoints even when using `@EnableAllEndpoints()`:
```typescript
@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:
```typescript
@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