Следуйте за мной в Twitter, с радостью приму ваши предложения по темам или улучшениям / Крис

Прогрессивная платформа Node.js для создания эффективных, надежных и масштабируемых серверных приложений.

В этой статье мы рассмотрим библиотеку Nest. Библиотека, которая делает создание API-интерфейсов действительно приятным. Если вы пришли из мира Angular, вы наверняка узнаете себя по используемым концепциям, отличному интерфейсу командной строки и, конечно же, отличному использованию Typescript.

ПРИМЕЧАНИЕ, это не Angular, но чертовски близко, в лучшем виде.

Эта статья является частью серии о Nest, потому что мы не можем охватить все в одной статье.

Мы рассмотрим следующее:

  • Почему именно Nest, давайте рассмотрим коммерческое предложение, а также отметим функции, которые делают Nest действительно хорошим выбором для вашего следующего API.
  • Ваш первый CRUD-проект - охватывает основы, давайте создадим проект и рассмотрим основные конструкции.

Почему Nest

Давайте посмотрим на рекламный ход на домашней странице.

  • Расширяемость, позволяет использовать любую другую библиотеку благодаря модульной архитектуре.
  • Универсальность, адаптируемая экосистема для всех видов серверных приложений.
  • Прогрессивный, использует новейшие функции JavaScript, шаблоны проектирования и зрелые решения.

Хорошо, все это звучит великолепно, но дайте мне то, чем я могу УДИВИТЬ своих коллег

Он полностью поддерживает TypeScript, но при желании используйте чистый JavaScript.

Он использует библиотеки Express и Fastify под капотом, но также может предоставлять их API, если это необходимо.

Звучит интересно, расскажите подробнее

Он поставляется с интерфейсом командной строки, поэтому вы можете формировать проект, а также добавлять артефакты.

Кроме того, вы можете легко писать модульные тесты, а также тесты E2E с помощью Jest, и вы можете легко создавать с его помощью API-интерфейсы GraphQL.

Прекратите, вы все придумываете

Нет уж, посмотрите Nest and GraphQL

Ресурсы

В этой статье мы упомянем несколько замечательных ресурсов. Если вы пропустите упомянутые нами ссылки, вот они.

  • Официальная страница документации - отличная страница для начала. Он охватывает все, от основ до рецептов.
  • Обзорный раздел Весь обзорный раздел - отличное чтение, в котором вы пытаетесь понять основные концепции, и вы также можете использовать интерфейс командной строки для построения проекта.
  • Рецепты Там много хороших рецептов. Все, от того, как работать с разными ORM до настройки Swagger (что, кстати, очень просто)

Ваш первый проект - покрытие основ

Хорошо, тогда. Давай сделаем это. Прежде чем мы начнем создавать наш первый проект, нам понадобится интерфейс командной строки для создания и запуска нашего проекта и многое другое. Мы можем легко установить CLI, используя следующую команду:

Далее нам нужно создать проект. Итак, давайте сделаем следующее:

Вы можете заменить hello-world на название проекта по вашему выбору.

Хорошо, у нас есть много файлов. Судя по приведенным выше изображениям, мы, похоже, получили проект Node.js с package.json и некоторое тестирование, настроенное с помощью Jest, и, конечно же, набор артефактов, которые кажутся специфичными для Nest, например controller, module и service. Давайте внимательно посмотрим на проект scaffolded:

Как это работает?

Прежде чем запустить проект, который мы только что создали, давайте сначала рассмотрим его поближе, чтобы понять его жизненный цикл. Прежде всего, давайте посмотрим на main.ts. Это точка входа для нашего приложения. В частности, это метод bootstrap(), который запускает все, запустив код:

// main.ts

const app = await NestFactory.create(AppModule);
await app.listen(3000);

Итак, NestFactory вызывает create(), который создает экземпляр AppModule, и мы получаем экземпляр app, который, похоже, прослушивает порт 3000. Пойдем на AppModule и посмотрим, что там происходит:

//app.module.ts

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Хорошо, похоже, у нас есть класс AppModule, который украшается @Module декоратором, который определяет контроллер AppController и что-то отнесенное к категории поставщиков AppService.

Как все это работает?

Что ж, контроллер AppController отвечает на запрос маршрута, поэтому давайте посмотрим, как он настроен:

// app.controller.ts

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

Декоратор @Get() гарантирует, что мы сопоставляем определенный запрос GET с определенным методом в нашем классе. В этом случае маршрут по умолчанию / ответит методом getHello(), который, в свою очередь, вызовет appService.getHello(). Посмотрим на app.service.ts:

// app.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

Кажется, это очень простой класс с методом getHello(), который возвращает строку.

А теперь вернемся к app.controller.ts.

Из того, что мы видим, appService вводится в конструктор AppController следующим образом:

// excerpt from app.controller.ts

constructor(private readonly appService: AppService) {}

Откуда он знает, как это сделать?

Здесь есть два ответа:

  1. Если вы добавите декоратор Injectable() к любой службе, это означает, что его можно внедрить в другие артефакты, например, в контроллер или службу.
  2. Это подводит нас ко второму шагу. Нам нужно добавить указанную службу в массив providers для модуля, чтобы механизм DI работал.

Oh?

Да, давайте попробуем немного укрепить это понимание, пройдя этапы добавления нового маршрута. Но прежде чем мы это сделаем, давайте запустим этот проект и докажем, что он работает так, как мы говорим:

npm start

Теперь перейдем к браузеру:

Добавление маршрута

Мы только что научились строить проект и научились запускать его. Мы думаем, что хорошо разбираемся в концепциях модуль, контроллер и service, но ничто так не укрепит эти знания, как добавление нового маршрута и добавьте все необходимые артефакты, чтобы это стало возможным. Мы сделаем следующее:

Мы создадим новый маршрут /products, и для этого нам необходимо выполнить следующие шаги

  1. Добавить новую услугу
  2. Добавьте новый контроллер и внедрите наш сервис
  3. Подключите механизм DI
  4. Запустите наше приложение и убедитесь, что все работает.

Первое, что мы собираемся сделать, это научиться правильно работать с проектами Nest. Прямо сейчас мы запустили npm start, который скомпилировал наш код TypeScript и разместил наше приложение на порте 3000, но во время разработки нам может потребоваться что-то, что прослушивает изменения и автоматически компилируется. Для этого давайте вместо этого выполним команду npm run start:dev, которая прослушивает изменения и при необходимости перекомпилирует.

npm run start:dev

ПРИМЕЧАНИЕ, прежде чем мы начнем использовать указанную выше команду, давайте создадим все необходимые файлы, а затем мы сможем выполнить указанное выше, когда мы возимся с конкретными файлами кода и хотим, чтобы наши изменения отражались.

Создание сервиса

Давайте создадим наши продукты сервисом. А пока сделайте данные статическими, мы можем посмотреть добавление HTTP-вызовов позже. Давайте сделаем все по принципу Nest и воспользуемся интерфейсом командной строки.

nest generate service products

ИЛИ более короткая версия

nest g s products

Хорошо, откройте файл products/products.service.ts. Должно получиться так:

import { Injectable } from '@nestjs/common';


@Injectable()
export class ProductsService {}

Теперь добавьте метод getProducts(), чтобы он выглядел так:

import { Injectable } from '@nestjs/common';


@Injectable()
export class ProductsService {
  getProducts() {
    return [{
      id: 1,
      name: 'A SPA app'
    },
    {
      id: 2,
      name: 'A Nest API'
    }]
  }
}

Добавление контроллера

Пришло время создать наш контроллер, так что давайте сделаем это дальше. Опять же, мы просто CLI, вот так:

nest generate controller products

ИЛИ, более короткая версия

nest g co products

Откройте products/products.controller:

import { Controller } from '@nestjs/common';

@Controller('products')
export class ProductsController {}

Следующим шагом будет добавление метода getProducts() и обеспечение вызова нашей службы и, конечно же, не забыть украсить ее декоратором @Get().

Теперь ваш код должен выглядеть так:

import { Controller, Get } from '@nestjs/common';
import { ProductsService } from './products.service';

@Controller('products')
export class ProductsController {
  constructor(private productsService: ProductsService) {}

  @Get()
  getProducts() {
    return this.productsService.getProducts();
  }
}

Давайте попробуем это:

npm run start:dev

Выше мы видим, как наш /products маршрут, казалось, был добавлен, и что ProductsController будет отвечать на любые запросы по этому маршруту. Но как это может быть, мы ничего не сделали для app.module.ts, чтобы подключить DI, или сделали?

Давайте посмотрим на app.module.ts:

Выше мы видим, что ProductsController и ProductsService были добавлены к controllers и providers соответственно. Интерфейс командной строки добавил его для нас, когда мы создали контроллер и службу.

Мы почти забыли кое-что, что запускало наше приложение в браузере, поэтому давайте сделаем следующее:

ПРИМЕЧАНИЕ. CLI очень мощный, он не только создает необходимые файлы, но и выполняет некоторые подключения, но знает, что вам нужно делать, если вы не используете CLI.

Добавление оставшихся маршрутов CRUD

Итак, мы добавили маршрут для поддержки маршрута /products. Как мы все знаем, нам нужно больше маршрутов, таких как POST, PUT, DELETE и wildcard route и т. Д.

Как их добавить?

Все просто, нам просто нужно создать методы для всех и каждого и добавить декораторы для их поддержки, например:

// products.controller.ts

import { Controller, Get, Param, Post, Body, Put, Delete } from '@nestjs/common';
import { ProductsService } from './products.service';

interface ProductDto {
  id: string;
  name: string;
}

@Controller('products')
export class ProductsController {
  constructor(private productsService: ProductsService) {}

  @Get()
  getProducts() {
    return this.productsService.getProducts();
  }

  @Get(':id') 
  getProduct(@Param() params) {
    console.log('get a single product', params.id);
    return this.productsService.getProducts().filter(p => p.id == params.id);
  }

  @Post()
  createProduct(@Body() product: ProductDto) {
    console.log('create product', product);
    this.productsService.createProduct(product);
  }

  @Put()
  updateProduct(@Body() product: ProductDto) {
    console.log('update product', product);
    this.productsService.updateProduct(product);
  }

  @Delete()
  deleteProduct(@Body() product: ProductDto) {
    console.log('delete product', product.id);
    this.productsService.deleteProduct(product.id);
  }
}

и products.service.ts теперь выглядит так:

import { Injectable } from '@nestjs/common';

@Injectable()
export class ProductsService {
  products = [{
    id: 1,
    name: 'A SPA app'
  },
  {
    id: 2,
    name: 'A Nest API'
  }];

  getProducts() {
    return this.products;
  }

  createProduct(product) {
    this.products = [...this.products, {...product}];
  }

  updateProduct(product) {
    this.products = this.products.map(p => {
      if (p.id == product.id) {
        return { ...product};
      }
      return p;
    });
  }

  deleteProduct(id) {
    this.products = this.products.filter(p => p.id != id);
  }
}

Резюме

Надеюсь, вы уже поняли, насколько хорошо структурирован Nest и насколько легко создать API и прочитать параметры запроса, а также тело для поддержки полного CRUD API. Мы также представили интерфейс командной строки, который действительно является вашим лучшим другом в создании необходимого кода и гарантирует, что вам не нужно думать о том, как все связать.

В нашей следующей части мы рассмотрим, как протестировать наш код, что принесет поистине приятный опыт. Так что следите за обновлениями.

Первоначально опубликовано на https://dev.to 17 июня 2019 г.