У современных разработчиков есть много альтернатив, когда речь заходит о создании веб-сервисов и других серверных приложений. Node стал крайне популярным выбором, однако многие программисты предпочитают более надежный язык, чем JavaScript, особенно те, кто пришел из современных объектно-ориентированных языков, например, таких как C#, C++ или Java. Если TypeScript просто хорошо подходит NodeJS , то фреймворк NestJS выводит его на совершенно новый уровень, предоставляя современные инструменты бэкенд-разработчику для создания долговечных и высокопроизводительных приложений с использованием компонентов, провайдеров, модулей и других полезных высокоуровневых абстракций.
В этой статье мы рассмотрим процесс создания простого API-сервера на NestJS для обработки базового сценария приложения: создание, хранение и получение списка продуктов универсама.
Если хотите ознакомиться с исходным кодом проекта, вы можете найти его здесь.
Создание проекта
Для работы с Nest нужна среда Node. Если у вас ее еще нет, зайдите на их сайт и скачайте ее.
Установить фреймворк достаточно просто:
$ npm i -g @nestjs/cli
Этот проект был создан с помощью Nest CLI после выполнения следующей команды:
$ nest new nest-js-example
Такая команда создаст совершенно новый проект Nest с необходимыми файлами конфигурации, структурой папок и шаблоном сервера.
Точка входа приложения
Основной файл, который конфигурирует и запускает сервер – это
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);
}
bootstrap();
Этот файл импортирует класс NestFactory, который используется для создания приложения, и основной файл AppModule (с которым мы в скором времени познакомимся), а затем загружает приложение, инстанцируя его, и слушает на 3000 порту.
App Module
Файл, в котором задекларированы компоненты приложения, называется
src/app.module.ts
:import { Module } from '@nestjs/common';
import { ItemsController } from './items/items.controller';
import { ItemsService } from './items/items.service';
@Module({
imports: [],
controllers: [ ItemsController ],
providers: [ ItemsService ],
})
export class AppModule {}
Это файл, где остальные компоненты импортируются и декларируются в Модуль, который импортируется в предыдущем файле (main.ts). Инструменты Nest CLI автоматически обновят этот файл по мере необходимости, когда будет дана команда создать новый компонент. Здесь импортируются контроллер и сервис для items и добавляются в модуль.
Items Controller
Следующий файл, с которым мы ознакомимся – это
src/items/items.controller.ts
:import { Controller, Req, Get, Post, Body } from '@nestjs/common'
import { CreateItemDto } from './dto/create-item.dto'
import { ItemsService } from './items.service'
import { Item } from './items.interface'
@Controller('items')
export class ItemsController {
constructor(private readonly itemsService: ItemsService) {}
@Post()
create(@Body() data: CreateItemDto): Object {
return this.itemsService.create(data)
}
@Get()
findAll(): Array<Item> {
return this.itemsService.findAll()
}
}
Этот файл определяет контроллер для создания item’ов и получения списка ранее созданных. Здесь импортируется несколько ключевых компонентов:
- CreateItemDto: Объект Data-Transfer, который определяет как данные item’ов будут отправляться по сети (т.е. это структура данных JSON);
- ItemsService: Provider, который обрабатывает манипуляции или хранение данных Item;
- Item: Интерфейс, который определяет внутреннюю структуру данных для Item;
Декоратор
@Controller('items')
указывает фреймворку, что этот класс будет обслуживать конечную точку REST /items, а конструктор ItemsController берет экземпляр ItemsService, который используется внутри для обслуживания двух HTTP методов:- POST /items (создает новый item из JSON-запроса);
- GET /items (получения списка ранее созданных item’ов).
Запросы к этим двум методам обрабатываются методами create и FindAll, которые привязаны к соответствующим методам HTTP с помощью декораторов
@Post()
и @Get()
. Дополнительные методы тоже могут поддерживаться декораторами аналогичным образом, например, @Put()
или @Delete()
и т.д.Интерфейсы объекта Item
Дальше разберемся с двумя файлами, которые определяют интерфейсы для хранения item, один для внутреннего использования, такого как проверка типа по время компиляции (Item), и внешний интерфейс для определения ожидаемой структуры входящего JSON (
CreateItemDto
):export interface Item {
name: string,
description: string,
price: number
}
export class CreateItemDto {
@IsNotEmpty()
readonly name: string;
@IsNotEmpty()
readonly description: string;
@IsNotEmpty()
readonly price: number;
}
Интерфейс Item определяет три свойства обычного магазинного товара: название, описание и цену. Это гарантирует отсутствие путаницы в архитектуре приложения в вопросах того, что такое item и какими свойствами он обладает.
Класс CreateItemDto отражает свойства Item, декорируя каждое свойство
@IsNotEmpty()
, чтобы гарантировать, что все эти свойства запрашиваются конечной точкой REST API.Все свойства обоих классов строго типизированы, что является одним из главных преимуществ TypeScript (отсюда и название). На первый взгляд это повышает уровень понимания контекста, а еще значительно сокращает время разработки при правильном использовании вместе с инструментами анализа кода (такими как IntelliSense в VSCode). Особенно характерно это для больших проектов с сотнями или даже тысячами различных классов и интерфейсов. Для тех, кто не обладает совершенной фотографической памятью с бесконечной емкостью (например, для меня), так гораздо проще, чем пытаться запомнить тысячи конкретных деталей.
Сервис Items
Самый последний – сервис для создания и получения
items: items.service.dart
:import { Injectable } from '@nestjs/common'
import { Item } from './items.interface'
@Injectable()
export class ItemsService {
private items: Array<Item> = []
create(item: Item): Object {
this.items.push(item)
return { id: this.items.length.toString() }
}
findAll(): Array<Item> {
return this.items;
}
}
Класс ItemsService определяет простой массив объектов Item, который будет служить в качестве in-memory хранилища данных для нашего проекта-примера. Два метода, которые пишут и читают из этого хранилища это:
- create (сохраняет Item в список и возвращает его id);
- findAll (возвращает список ранее созданных объектов Item).
Тестируем
Чтобы запустить сервер, используйте стандартную команду npm run start. Когда приложение запущено, его можно протестировать с помощью отправки HTTP-запросов через CURL:
$ curl -X POST localhost:3000/items -d '{"name":"trinket", "description":"whatever", "price": 42.0}'
Выполнение этой команды вернет ответ в формате JSON с id,созданного item. Чтобы показать список item’ов, которые уже созданы используйте:
$ curl localhost:3000/items
GET-запрос к /items, приведенный выше, вернет ответ в формате JSON с информацией об item’ах, которые уже хранятся в памяти. Ответ должен выглядеть как-то так:
[{"{\"name\":\"trinket\", \"description\":\"whatever\", \"price\": 42.0}":""}]
Заключение
NestJS относительно новое решение в области бэкенд-разработки, с большим набором функций для быстрого построения и развертывания корпоративных сервисов, которые отвечают требованиям современных клиентов приложений и придерживаются принципов SOLID и приложения двенадцати факторов.
Чтобы узнать больше, посетите сайт NestJS.
Спасибо, что ознакомились с моей статьей. Счастливого кодинга!
Tonn_Tamerlan
Spring для JS изобрели, прикольно, надо попробовать