Создание веб-приложений, подобных администратору, с помощью NestJS и React Admin. Часть 1.
Базовая загрузка API и пользовательского интерфейса.
Введение
В этой серии статей я опишу, как быстро настроить панель администрирования на основе API для вашего проекта с помощью NestJS и React Admin.
Чтобы продолжить (в том случае, если вы читаете не для удовольствия), вам может потребоваться NodeJS 10+, npm, yarn. и MySQL, установленный на вашем компьютере. Кроме того, вы должны обладать базовыми знаниями в области TypeScript и React.
Наш проект будет состоять из 2-х частей:
- REST API, написанный на TypeScript
- Панель администратора, написанная на React
В демонстрационных целях мы создадим простое приложение для управления списком гостей. Это будет включать создание гостей, отображение списка и обновление информации о гостях.
Итак, начнем.
Создание API
Для создания API воспользуемся фреймворком NestJS. Мне нравится NestJS, потому что он основан на TypeScript и, таким образом, позволяет создавать более читаемый, лучше структурированный и менее подверженный ошибкам внутренний код.
Мы будем использовать инструмент NestJS CLI для инициализации нашего бэкэнда:
npm i -g @nestjs/cli
nest new api
cd api
Теперь, когда скелет проекта готов, мы добавим другие необходимые нам зависимости.
Мы будем использовать TypeORM (снова TypeScript) для работы с MySQL:
yarn add @nestjs/typeorm typeorm mysql class-validator class-transformer
Библиотека NestJS CRUD для упрощения создания наших конечных точек:
yarn add @nestjsx/crud
И NestJS Config для управления конфигурацией нашего приложения:
yarn add nestjs-config
После того, как вы закончите с зависимостями, давайте сгенерируем скелет конечной точки нашего API гостей.
nest generate module guests nest generate controller guests nest generate service guests
И создайте класс модели для нашей гостевой сущности (src / guest / guest.entity.ts)
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; import { IsEmail } from 'class-validator'; @Entity({ name: 'guests' }) export class GuestEntity { @PrimaryGeneratedColumn() id: number; @Column() firstName: string; @Column() lastName: string; @Column({ unique: true, }) @IsEmail() email: string; @Column({ default: false }) isPresent: boolean; }
Теперь мы добавляем код, чтобы соединить части вместе.
Обновите src / guest / guest.module.ts с зависимостями TypeORM.
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { GuestsController } from './guests.controller'; import { GuestEntity } from './guest.entity'; import { GuestsService } from './guests.service'; @Module({ imports: [ TypeOrmModule.forFeature([GuestEntity]), ], controllers: [ GuestsController, ], providers: [ GuestsService, ], }) export class GuestsModule { }
Сделайте так, чтобы src / guest / guest.service.ts расширял RepositoryService из NestJS CRUD
import { Injectable } from '@nestjs/common'; import { GuestEntity } from './guest.entity'; import { RepositoryService } from '@nestjsx/crud/typeorm'; import { InjectRepository } from '@nestjs/typeorm'; @Injectable() export class GuestsService extends RepositoryService<GuestEntity> { constructor(@InjectRepository(GuestEntity) repository) { super(repository); } }
и добавьте его в src / guest / guest.controller.ts. Кроме того, добавьте в контроллер декоратор Crud, чтобы включить функции, связанные с NestJS CRUD API.
import { Controller } from '@nestjs/common'; import { Crud } from '@nestjsx/crud'; import { GuestsService } from './guests.service'; import { GuestEntity } from './guest.entity'; @Crud(GuestEntity) @Controller('guests') export class GuestsController { constructor(public service: GuestsService) { } }
Наконец, мы настраиваем TypeORM в основном модуле (src / app.module.ts):
import { Module } from '@nestjs/common'; import { ConfigModule, ConfigService } from 'nestjs-config'; import { TypeOrmModule } from '@nestjs/typeorm'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { GuestsModule } from './guests/guests.module'; import * as path from 'path'; @Module({ imports: [ ConfigModule.load(path.resolve(__dirname, 'config', '*.{ts,js}')), TypeOrmModule.forRootAsync({ useFactory: (config: ConfigService) => config.get('database'), inject: [ConfigService], }), GuestsModule, ], controllers: [ AppController, ], providers: [ AppService, ], }) export class AppModule { }
И добавьте соответствующие файлы конфигурации
export default { host: process.env.DB_HOST, type: 'mysql', port: process.env.DB_PORT || 3306, username: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE, entities: ['src/**/*.entity{.ts,.js}'], synchronize: process.env.DB_SYNCRONIZE === 'true', logging: process.env.DB_LOGGING === 'true', };
.env:
DB_HOST = localhost DB_PORT = 3306 DB_USER = DB_PASSWORD = DB_DATABASE = DB_SYNCRONIZE = true DB_LOGGING = true
И мы готовы к старту!
Не так быстро :) Позже React Admin потребует, чтобы CORS был включен на стороне API. Итак, нам нужно изменить src / main.ts. И, кстати, позволяет упростить жизнь React и освободить 3000 портов!
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule, { cors: true }); await app.listen(3001); } bootstrap();
Теперь действительно готово!
yarn start
и продолжаем создавать пользовательский интерфейс панели администрирования.
Создание пользовательского интерфейса администратора
Как упоминалось ранее, для этой цели мы будем использовать React Admin - библиотеку компонентов на основе React для создания интерфейсов, подобных админке.
Начнем с инициализации приложения React
npm install -g create-react-app create-react-app admin-ui cd admin-ui
Затем добавьте в проект React Admin.
yarn add react-admin prop-types
и небольшая библиотека, разработанная нами (FusionWorks): @ FusionWorks / ra-data-nest-crud, которая интегрирует React Admin с нашей серверной частью на основе NestJS CRUD.
yarn add @fusionworks/ra-data-nest-crud
После этого мы можем инициализировать компонент React Admin и создать гостевой редактор. Во-первых, мы обновляем src / App.js с помощью корневого компонента администратора и компонента ресурсов для гостей:
import React from 'react'; import { Admin, Resource, ShowGuesser, ListGuesser } from 'react-admin'; import crudProvider from '@fusionworks/ra-data-nest-crud'; import { GuestCreate, GuestEdit } from './Guests'; const dataProvider = crudProvider('http://localhost:3001'); const App = () => ( <Admin dataProvider={dataProvider}> <Resource name="guests" list={ListGuesser} create={GuestCreate} edit={GuestEdit} show={ShowGuesser} /> </Admin> ); export default App;
Затем добавьте соответствующие формы в src / Гости / index.js.
Обратите внимание, что мы используем ListGuesser и ShowGuesser React Admin для просмотра списка и просмотра. При необходимости они могут быть заменены специальной реализацией так же, как создание и редактирование форм ниже.
import React from 'react'; import { Create, SimpleForm, TextInput, BooleanInput, Edit, Filter, required, email, } from 'react-admin'; const validateEmail = [required(), email()]; const validateRequired = required(); export const GuestCreate = props => ( <Create {...props}> <SimpleForm redirect="show"> <TextInput source="firstName" validate={validateRequired} /> <TextInput source="lastName" validate={validateRequired} /> <TextInput source="email" validate={validateEmail} /> </SimpleForm> </Create> ); const GuestEditTitle = ({ record }) => (<span>{`${record.firstName} ${record.lastName}`}</span>); export const GuestEdit = props => ( <Edit {...props} title={<GuestEditTitle />}> <SimpleForm redirect="list"> <TextInput source="firstName" validate={validateRequired} /> <TextInput source="lastName" validate={validateRequired} /> <TextInput source="email" validate={validateEmail} /> <BooleanInput source="isPresent" /> </SimpleForm> </Edit> );
Как только это будет сделано, мы готовы к работе!
yarn start
Заключение
Пока все выглядит отлично, но мы еще не коснулись таких вещей, как аутентификация, авторизация, случаи, когда модели базы данных и API должны отличаться и т. Д. Я расскажу о них в следующих статьях, и мы расскажем, если этот стек хорошо выживет. Так что следите за новостями о FusionWorks:
- Http://fusionworks.md/
- Https://www.facebook.com/FusionWorksMD/
- Https://www.linkedin.com/company/fusionworks-moldova
- Https://medium.com/fusionworks
Полезные ссылки
Исходный код статьи: https://github.com/FusionWorks/nestjs-crud-react-admin-boilerplate
Если вы хотите заняться дайпером самостоятельно, вот набор ссылок на документацию, которая может быть вам полезна:
- NestJS: https://docs.nestjs.com/
- NestJS CRUD: https://github.com/nestjsx/crud
- React Admin: https://marmelab.com/react-admin/