TL;DR
Статья представляет NestJS, бэкенд-фреймворк Typescript для разработки API: сильно вдохновленный Angular, мы найдем контроллеры, сервисы, охранники и другие декораторы.
Что такое NestJS?
NestJS — это Javascript (точнее, TypeScript) MVC-фреймворк для разработки бэкенда поверх NodeJs и Express или Fastify (которые обрабатывают низкоуровневые HTTP-маршруты). Он также позволяет разрабатывать API, что мы и рассмотрим в этом посте, посвященном знакомству с NestJs.
Философия похожа на бэкенд-фреймворки, такие как ASPNET WebApi C# / .NET, Java Spring или Angular на фронтенде: многоуровневый подход (контроллеры, сервисы через инъекцию зависимостей, которая обеспечит уровень абстракции), с помощью атрибутов / аннотаций, которые мы будем называть декораторами, которые мы находим в Angular, модульный (как Angular). Написание кода осуществляется на TypeScript (но Javascript остается возможным), мы найдем наши хорошие практики разработки (типизация, ООП, паттерны проектирования).
NestJS также предлагает гнездо CLI, которое позволит вам генерировать леса классов, сервисов, контроллеров и т.д., хорошее количество модулей / плагинов / механизмов: ORMs с TypeORM, например, или аутентификация с PassportJS (и техническая механика управления JWT) и авторизация: кто имеет право доступа к такому-то или такому-то API / функции (гвардия с ролями, как в Angular), безопасность с CORS и поддержка OpenAPI через Swagger для документации ваших API.
NestJs с точки зрения архитектуры берет все, что мы уже знаем из backend или frontend фреймворков типа SPA (особенно Angular), в TypeScript, что позволяет взаимно объединить знания front и back.
Резюме
- NestJS
- Книги API
- Инициализация
- Скелеты контроллера / сервиса / сущности
- Модификация скелета
- Заключение
Книги API
В этом введении мы возьмем приложение для управления книгами из серии Angular / Django REST, пока что занимаясь только книгами, без аутентификации и без интерфейса, сосредоточившись только на API.
Установка NestJS и инициализация приложения
$ mkdir library_nest && cd library_nest
Давайте начнем с CLI, глобально:
$ npm i -g @nestjs/cli
$ nest --version
8.2.5
Создание скелета приложения, которое мы будем называть backend, благодаря CLI, я выбираю npm
в качестве менеджера пакетов, перейдите к backend в конце строительных лесов
$ nest new backend
⚡ We will scaffold your app in a few seconds..
CREATE backend/.eslintrc.js (665 bytes)
CREATE backend/.prettierrc (51 bytes)
CREATE backend/nest-cli.json (118 bytes)
CREATE backend/package.json (1992 bytes)
CREATE backend/README.md (3340 bytes)
CREATE backend/tsconfig.build.json (97 bytes)
CREATE backend/tsconfig.json (546 bytes)
CREATE backend/src/app.controller.spec.ts (617 bytes)
CREATE backend/src/app.controller.ts (274 bytes)
CREATE backend/src/app.module.ts (249 bytes)
CREATE backend/src/app.service.ts (142 bytes)
CREATE backend/src/main.ts (208 bytes)
CREATE backend/test/app.e2e-spec.ts (630 bytes)
CREATE backend/test/jest-e2e.json (183 bytes)
? Which package manager would you ❤️ to use? npm
🚀 Successfully created project backend
👉 Get started with the following commands:
$ cd backend
Мы можем запустить сервер
$ npm run start
или $ npm run start:dev
для учета модификаций кода и автоматической перезагрузки сервера (watcher), в режиме разработки это более чем рекомендуется.
Компиляция / транспонирование в javascript выполняется в dist
, который будет использовать сервер.
Доступ к сайту http://localhost:3000/ можно получить через браузер.
Если возникла проблема с портом (например, он уже занят), можно изменить его в файле backend/src/main.ts
.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000); // modifier le port ICI
}
bootstrap();
Контроллер / служба / организация
В этой статье мы будем придерживаться простого подхода, чтобы продемонстрировать архитектуру контроллера/сервиса без доступа к базе данных.
Последовательность вызовов можно представить следующим образом:
(источник: https://excalidraw.com/#json=RLHChssGR5kaOEKRfNmdI,yIh11YsH_-LOCn11-MJjzA)
Давайте создадим с помощью CLI несколько скелетов, в модуле книги.
В этой первой статье у нас будет модуль book, в котором мы найдем контроллер bookControler, сервис bookService и класс сущности book. В этой статье мы не будем обращаться к базе данных, книги будут просто жестким списком в коде.
$ nest g module book # il crée src/book/book.module.ts et met à jour le module principal src/app.module.ts qui le référence
$ nest generate --flat controller book/controller/book # controller en mode flat pour générer les fichiers dans un emplacement choisi, ici book/controller/book, il met aussi à jour le module book.module.ts
$ nest generate --flat service book/service/book # idem mais pour le service, le module book.module.ts est mis à jour
$ nest g --flat class book/book.entity # la classe entité
У нас есть следующая структура src:
src
└───book
├───controller
└───service
$ ls -R src | awk '
/:$/&&f{s=$0;f=0}
/:$/&&!f{sub(/:$/,"");s=$0;f=1;next}
NF&&f{ print s"/"$0 }'
src/app.controller.spec.ts
src/app.controller.ts
src/app.module.ts
src/app.service.ts
src/book/
src/main.ts
src/book/book.entity.spec.ts
src/book/book.entity.ts
src/book/book.module.ts
src/book/controller/
src/book/service/
src/book/controller/book.controller.spec.ts
src/book/controller/book.controller.ts
src/book/service/book.service.spec.ts
src/book/service/book.service.ts
Внесение изменений в файлы, чтобы сделать их пригодными для использования
Книжное образование становится :
export class BookEntity {
id: number;
title: string;
}
Сервис возвращает жесткий список книг или конкретную книгу по ее ID, он будет инжектирован в контроллер, необходимо ключевое слово @Injectable
, мы инициализируем несколько жестких книг в сервисе:
import { Injectable } from '@nestjs/common';
import { BookEntity } from '../book.entity';
@Injectable()
export class BookService {
books: BookEntity[] = [
<BookEntity>{ id: 1, title: 'NestJS 101' },
<BookEntity>{ id: 2, title: 'Angular' },
];
async getAll(): Promise<BookEntity[]> {
return this.books;
}
async getById(id): Promise<BookEntity> {
return this.books.find((_book: BookEntity) => _book.id === Number(id.id));
}
}
и контроллера, который его использует, конструктор, как и в Angular, позволяет инжектировать сервис. Декораторы @Controller() и @Get() позволяют нам определить наш API: на /api/books
и метод GET через @Get()
на функцию GetAll(), которая возвращает все книги или /api/books/2
GetById() на определенный ID.
import { Controller } from '@nestjs/common';
import { BookService } from '../service/book.service';
@Controller('api/books')
export class BookController {
constructor(private bookService: BookService) {}
@Get()
async getAll(): Promise<BookEntity[]> {
return await this.bookService.getAll();
}
@Get(':id')
async getById(@Param() id): Promise<BookEntity> {
return await this.bookService.getById(id);
}
}
Сервер перезагружает все
[13:31:58] File change detected. Starting incremental compilation...
[13:31:59] Found 0 errors. Watching for file changes.
[Nest] 3952 - 08/05/2022, 14:12:11 LOG [NestFactory] Starting Nest application...
[Nest] 3952 - 08/05/2022, 14:12:11 LOG [InstanceLoader] AppModule dependencies initialized +95ms
[Nest] 3952 - 08/05/2022, 14:12:11 LOG [InstanceLoader] BookModule dependencies initialized +2ms
[Nest] 3952 - 08/05/2022, 14:12:11 LOG [RoutesResolver] BookController {/api/books}: +121ms
[Nest] 3952 - 08/05/2022, 14:12:11 LOG [RouterExplorer] Mapped {/api/books, GET} route +7ms
[Nest] 3952 - 08/05/2022, 14:12:11 LOG [RouterExplorer] Mapped {/api/books/:id, GET} route +2ms
[Nest] 3952 - 08/05/2022, 14:12:11 LOG [NestApplication] Nest application successfully started +4ms
и API возвращает все книги в формате JSON
или одну из книг
Заключение
Это введение позволяет понять базовую архитектуру NestJS, в следующих статьях мы рассмотрим доступ к базе данных с помощью библиотеки TypeORM, аутентификацию и многое другое!
Найдите исходники на https://github.com/zorky/library_nestjs/tree/nestjs-101, установите пакеты в бэкенд: $ npm install
и запустите! $ npm run start:dev