Создание CRUD RESTfull API может занять некоторое время, особенно у новичков, или может быть очень скучным для некоторых опытных разработчиков. Но сегодня я собираюсь показать, как это можно сделать быстро и по-другому, с помощью NestJS и @nestjsx/crud.

Требования

npm i -g @nestjs/cli
npm i --save @nestjs/typeorm typeorm pg
npm i --save @nestjs/swagger swagger-ui-express
npm i class-validator --save
npm i @nestjsx/crud class-transformer class-validator
npm i @nestjsx/crud-typeorm @nestjs/typeorm typeorm

Первые шаги

Сначала нам нужно создать новый проект NestJS.

nest new project-name

Затем мы можем подключиться к базе данных PostgreSQL и pgAdmin 4 с помощью docker-compose. Просто скопируйте файл docker-compose.yml в корневой каталог проекта и запустите docker-compose.

// docker-compose.yml
version: '3'

services:
  postgres_compose:
    image: postgres
    environment:
      POSTGRES_PASSWORD: '1StrongPassword'
      POSTGRES_USER: 'postgres'
      POSTGRES_DB: 'myDatabase'
    ports:
      - '15432:5432'
    volumes:
      - /var/docker/postgres/db:/var/lib/postgresql/data
    networks:
      - postgres-compose-network

  pgadmin_compose:
    image: dpage/pgadmin4
    environment:
      PGADMIN_DEFAULT_EMAIL: '[email protected]'
      PGADMIN_DEFAULT_PASSWORD: '1StrongPassword'
    ports:
      - '16543:80'
    depends_on:
      - postgres_compose
    networks:
      - postgres-compose-network

networks:
  postgres-compose-network:
    driver: bridge

Затем нам нужно открыть страницу pgAdmin: http://localhost:16543/ и создать подключение к серверу с Host: postgres_compose. Теперь мы можем создать базу данных.

Далее нам нужно подключить NestJS к серверу базы данных. Итак, прежде всего, создайте файл ormconfig.json в корневом каталоге проекта с необходимыми конфигурациями для подключения к базе данных docker. Затем нам нужно только вызвать forRoot() без каких-либо опций в модуле приложения.

// ormconfig.json
{
  "type": "postgres",
  "host": "localhost",
  "port": 15432,
  "username": "postgres",
  "password": "1StrongPassword",
  "database": "myDatabase",
  "entities": ["dist/**/*.entity{.ts,.js}"],
  "synchronize": true,
  "logging": true
}

// app.module.ts
@Module({
  imports: [TypeOrmModule.forRoot(), UsersModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Теперь мы можем установить и настроить Swagger API. Нам нужно создать DocumentBuilder в нашем файле main.ts.

// main.ts
const options = new DocumentBuilder()
  .setTitle('My RESTful CRUD API')
  .setDescription('example')
  .setVersion('version')
  .build();
  const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('/api', app, document);

CRUD

Теперь наступает лучшая часть!
Обычно я использую следующую структуру каталогов.

src/
├── users/
    ├── user/
    │   ├── controllers/
    │   │   ├── dto/
    │   │   │   └── create.dto.ts
    │   │   └── user.controller.ts
    │   ├── entities/
    │   │   ├── user-typeorm/
    │   │   │   └── user-typeorm.entity.ts
    │   │   └── user.interface.ts
    │   ├── services/
    │   │   └── user.service.ts
    └── user.module.ts

Для этого примера мы собираемся создать простой CRUD API для регистрации пользователей.
Во-первых, объект, простой объект пользователя, который реализует пользовательский интерфейс с именем, адресом электронной почты и возрастом.

// user.entity.ts
@Entity('user')
export class UserEntity implements User {
  @PrimaryGeneratedColumn() id: number;
@IsNotEmpty()
  @Column()
  name: string;
@IsNotEmpty()
  @Column()
  email: string;
@IsNotEmpty()
  @Column()
  age: number;
}

Затем нам нужно создать UserService, который мы можем использовать в контроллерах. С @nestjsx/crud наш сервис состоит всего из нескольких строк и делает все, что нужно.

// user.service.ts
@Injectable()
export class UserService extends TypeOrmCrudService<UserEntity> {
  constructor(@InjectRepository(UserEntity) repo: Repository<UserEntity>) {
    super(repo);
  }
}

Контроллеру также нужно несколько строк кода, чтобы идентифицировать сущность, DTO и внедрить UserService. Сделанный!

// user.controller.ts
@ApiTags('User')
@Crud({
  model: {
    type: UserEntity,
  },
  routes: {
    exclude: ['createManyBase', 'replaceOneBase'],
    deleteOneBase: {
      returnDeleted: true,
    },
  },
  dto: {
    create: CreateUser,
    update: CreateUser,
  },
})
@Controller('user')
export class UserController implements CrudController<User> {
  constructor(public service: UserService) {}
}

DTO не требуются, но рекомендуется всегда использовать DTO, особенно в теле запросов REST.

// create-user.dto.ts
export class CreateUser {
  @ApiProperty()
  @IsNotEmpty()
  public name: string;
@ApiProperty()
  @IsNotEmpty()
  public email: string;
@ApiProperty()
  @IsNotEmpty()
  public age: number;
}

И, наконец, мы создаем UsersModule и можем запускать API нашего сервера.

// users.module.ts
@Module({
  imports: [TypeOrmModule.forFeature([UserEntity])],
  providers: [UserService],
  controllers: [UserController],
})
export class UsersModule {}

Вывод

Как видите, через пару минут у нас есть полный REST API, который работает очень хорошо. Следующим шагом может быть создание некоторых валидаторов, пользовательских запросов, перехватчиков и так далее.

Git: https://gitlab.com/DylanMatiasMarques/medium-nestjs-crud

Для получения дополнительной информации обратитесь к документации:
https://github.com/nestjsx/crud
https://docs.nestjs.com/