NestJS — это хорошо масштабируемая платформа NodeJS, революционизирующая создание серверных приложений. Его способность создавать контексты приложений позволяет разработчикам легко создавать микроприложения и использовать преимущества компонентов и модулей в этой среде.
Можно просто создать оболочку вокруг контейнера Nest, в котором будут храниться все экземпляры классов. Затем вы можете захватить существующий экземпляр внутри этой оболочки и запускать в нем функции, такие как очистка кеша приложения, восстановление файлов конфигурации и т. Д.
- Что посеять? ?
- Структура каталогов ?
- Провайдеры
- provider.module.ts
- Модели и интерфейсы
- Интерфейсы
- languages.interface.ts
- Модель / сущность
- languages.entity.ts
- Данные
- data.ts
- Услуги и модули
- Языковая служба
- languages.services.ts
- Языковой модуль
- languages.module.ts
- Главный модуль сеялки
- seeder.module.ts
- Провайдер сеялки
- сеялка.ts
- Создание контекста приложения и запуск сеялки
- Загрузите свое микроприложение
- seed.ts
- Команда
- package.json
- Заключение
Что посеять? ?
Любые статические данные, которые обычно используются между объектами или используются в основном для тестирования, — это то, на чем следует сосредоточиться при заполнении. Это могут быть базовые сущности, такие как языки, или сущности, такие как учетные записи администраторов, которые в основном требуются, когда ваше приложение включает аутентификацию и управление ролями пользователей ?♂️.
Язык (а), являющийся одним из самых простых объектов для объяснения, — это то, на чем мы собираемся сегодня сосредоточиться.
Структура каталогов ?
Nest придерживается строгого модульного подхода, которого мы будем придерживаться. Вот как мы будем хранить все файлы, описанные в этой статье.
src /
├── database
│ └── seeders
│ ├── seeder.module.ts
│ ├── seeder.ts
│ └── language
│ ├── data.ts
│ ├── languages.module.ts
│ └── languages.service.ts
├── models
│ └── language
│ ├── entities
│ │ └── language.entity.ts
│ └── interfaces
│ └── language.interface.ts
├── providers
│ └── database
│ └── mysql
│ └── provider.module.ts
└── seed.ts
Провайдеры
Прежде чем мы начнем, нам нужно подключиться к базе данных. В этом посте мы собираемся использовать TypOrmModule для подключения к базе данных MySQL, однако вы можете создавать своих собственных провайдеров аналогично MongoDB с использованием MongooseModule. Если ваше приложение требует подключения к нескольким базам данных, подумайте о прочтении Динамических модулей.
provider.module.ts
/**
* Import and provide base typeorm (mysql) related classes.
*
* @module
*/
@Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [MysqlConfigModule],
useFactory: async (mysqlConfigService: MysqlConfigService) => ({
type: 'mysql' as DatabaseType,
host: mysqlConfigService.host,
port: mysqlConfigService.port,
username: mysqlConfigService.username,
password: mysqlConfigService.password,
database: mysqlConfigService.database,
entities: [Language],
synchronize: true,
}),
inject: [MysqlConfigService],
} as TypeOrmModuleAsyncOptions),
],
})
export class MysqlDatabaseProviderModule {}
Обратите внимание, как мы используем мою Language
Модель непосредственно в массиве сущностей. Это отличается от техники, упомянутой здесь, особенно из-за проблемы, с которой обычно сталкиваются при создании производственных сборок, размещенных на Github.
Модели и интерфейсы
Связывание модели с интерфейсом — хорошая практика. Благодаря поддержке Typescript из коробки, Nest упрощает для нас эту задачу.
Интерфейсы
Это простой пример того, как мы можем создать языковой интерфейс. Здесь особо нечего объяснять, но если в вашей модели есть типы и т. Д., Вы можете воспользоваться преимуществами Enums, а затем привязать их к вашей модели.
languages.interface.ts
/**
* Language variable type declaration.
*
* @interface
*/
export interface ILanguage {
name: string;
}
Модель / сущность
Всегда полезно иметь в модели временные метки. В остальном создать модель относительно просто. Вы можете узнать больше о том, как создавать модели с помощью TypeORM здесь: Документация TypeORM.
languages.entity.ts
/** * Entity Schema for Languages. * * @class */ @Entity({ name: 'languages', }) export class Language implements ILanguage { @PrimaryGeneratedColumn() id: number;
@Column() name: string;
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', }) createdAt: string;
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', }) updatedAt: string; }
Данные
Чтобы упростить задачу, мы будем сохранять все данные Language в константе. Однако, если вы планируете использовать фейкер, подумайте о том, чтобы взглянуть на документацию Faker.
data.ts
export const languages: ILanguage[] = [
{ name: 'English' },
{ name: 'French' },
{ name: 'Spanish' },
{ name: 'Russian' },
// ... and others ...
];
Услуги и модули
Сервисы действуют как посредник между контроллером и репозиторием. Это термин, который чаще всего используется при поиске в Интернете шаблона репозитория службы. Подробнее о том, как создавать модули в NestJS, вы можете прочитать здесь.
Языковая служба
Давайте начнем с создания LanguageService
, который будет использовать свой репозиторий в качестве зависимости. Однако репозиторий предоставляется нам самим TypeORM, поэтому нам не нужно его создавать.
languages.services.ts
/** * Service dealing with language based operations. * * @class */ @Injectable() export class LanguageSeederService { /** * Create an instance of class. * * @constructs * * @param {Repository<Language>} languageRepository */ constructor( @InjectRepository(Language) private readonly languageRepository: Repository<Language>, ) {}
/** * Seed all languages. * * @function */ create(): Array<Promise<Language>> { return languages.map(async (language: ILanguage) => { return await this.languageRepository .findOne({ name: language.name }) .exec() .then(async dbLangauge => { // We check if a language already exists. // If it does don't create a new one. if (dbLangauge) { return Promise.resolve(null); }
return Promise.resolve( await this.languageRepository.create(language), ); }) .catch(error => Promise.reject(error)); }); } }
Языковой модуль
Языковой модуль импортирует TypeOrmModule
для сущности Language вместе со своей службой, которая обрабатывает заполнение всех языков.
languages.module.ts
/**
* Import and provide seeder classes for languages.
*
* @module
*/
@Module({
imports: [TypeOrmModule.forFeature([Language])],
providers: [LanguageSeederService],
exports: [LanguageSeederService],
})
export class LanguageSeederModule {}
Главный модуль сеялки
seeder.module.ts
/**
* Import and provide seeder classes.
*
* @module
*/
@Module({
imports: [MysqlDatabaseProviderModule, LanguageSeederModule],
providers: [MysqlSeederService, Logger, Seeder],
})
export class SeederModule {}
Обратите внимание, как сюда импортируется наш основной модуль поставщика MySQL. Загрузка всех классов по умолчанию асинхронная, но вы можете сделать их синхронными, импортировав поставщиков в методе, определенном в документации NestJS.
Провайдер сеялки
Это последний класс сидера, который имеет функцию seed()
, которая далее вызывает функцию create()
в LanguageSeederService
.
сеялка.ts
@Injectable() export class Seeder { constructor( private readonly logger: Logger, private readonly languageSeederService: LanguageSeederService, ) {}
async seed() { await this.languages() .then(completed => { this.logger.debug('Successfuly completed seeding users...');
Promise.resolve(completed); }) .catch(error => { this.logger.error('Failed seeding users...');
Promise.reject(error); }); }
async languages() { return await Promise.all(this.languageSeederService.create()) .then(createdLanguages => { // Can also use this.logger.verbose('...'); this.logger.debug( 'No. of languages created : ' + // Remove all null values and return only created languages. createdLanguages.filter( nullValueOrCreatedLanguage => nullValueOrCreatedLanguage, ).length, );
return Promise.resolve(true); }) .catch(error => Promise.reject(error)); } }
Создание контекста приложения и запуск сеялки
Последние шаги включают написание функции начальной загрузки, которая будет использовать NestFactory
для создания контекста приложения.
Загрузите свое микроприложение
seed.ts
async function bootstrap() { NestFactory.createApplicationContext(SeederModule) .then(appContext => { const logger = appContext.get(Logger); const seeder = appContext.get(Seeder);
seeder .seed() .then(() => { logger.debug('Seeding complete!'); }) .catch(error => { logger.error('Seeding failed!');
throw error; }) .finally(() => appContext.close()); }) .catch(error => { throw error; }); } bootstrap();
Обратите внимание на то, что у нас есть appContext().close()
как последнее действие обещания.
Команда
И последнее, но не менее важное: просто добавьте этот сценарий в свой package.json
. Затем вы можете запустить сидер, используя npm
или yarn
или любой менеджер пакетов, который вы используете.
package.json
{
// ... other package.json fields ...
"scripts": {
// ... other scripts ...
"seed": "ts-node -r tsconfig-paths/register src/seed.ts"
}
}
Заключение
Nest — действительно мощный серверный фреймворк. Я твердо верю, что это изменит кодирование в NodeJS. Для получения дополнительной информации о Nest посетите его веб-сайт и подумайте поддержать их в OpenCollective или через Paypal.
Кроме того, не забудьте ознакомиться со следующей частью этой статьи в разделе Добавление параметров в сеялку базы данных.
Дайте мне знать в комментариях, если у вас возникнут какие-либо проблемы с этим или вам понадобится какая-либо другая помощь.