Скидки до 20% + 2-ая профессия бесплатно и подарки на 50 000₽

Главная | Все статьи | Код

Гайд по Nest.js: что это такое и как написать свой первый код

Время чтения статьи ~11 минут 23
Гайд по Nest.js: что это такое и как написать свой первый код главное изображение

Nest.js — самый важный и популярный фреймворк для создания серверных веб-приложений Node.js. В этом большом гайде мы поможем новичкам сделать первый шаг в освоении этого фреймворка для серверного JavaScript и расскажем, в чем вообще особенности Nest.js.

Для комфортного усвоения этого гайда вам потребуется:

  • Знание JavaScript на среднем уровне
  • Знание основ TypeScript, особенно синтаксиса декораторов
  • Базовые знания Node.js. Желательно, опыт с Express.js
  • Знание базовых понятий MVC (Model-View-Controller)

Также нам понадобятся установленные на компьютер:

  • Node.js версии 10+. Инструкция по установке
  • Docker

Docker мы будем использовать для развертывания базы данных. Развертывание СУБД в контейнере — один из самых простых способов. Но если вы хотите использовать другой способ, или же работать с уже имеющейся СУБД — нет проблем. В таком случае Docker вам не понадобится.

Node.js-разработчик — с нуля до трудоустройства за 10 месяцев
  • Постоянная поддержка от наставника и учебного центра
  • Помощь с трудоустройством
  • Готовое портфолио к концу обучения
  • Практика с первого урока

Вы получите именно те инструменты и навыки, которые позволят вам найти работу

Узнать больше

Введение

Зачем нам нужен фреймворк?

Большинство задач в программировании — типовые. Если не брать каких-то специфических бизнес-кейсов, скорее всего все возможные задачи уже решены другими программистами и не по одному разу. Не зря в среде программистов среде так часто можно услышать шутки о «велосипедостроении». Фреймворки помогают нам писать меньше шаблонного кода и сосредоточиться на том, какую полезную работу должна делать наша программа.

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

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

Создадим проект

Чтобы каждый раз не приходилось настраивать проект с нуля, разработчики Nest.js вооружили нас консольной утилитой — @nestjs/cli. Установим ее глобально:

npm i @nestjs/cli -g

Теперь в вашей директории с проектами выполним команду nest new, указав имя проекта.

nest new nestjs-getting-started

Когда cli закончит свою работу, мы можем перейти в директорию nestjs-getting-started и посмотреть, что получилось:

Структура проекта

Все основные зависимости уже установлены, сборка TypeScript настроена. Кроме этого, создана папка src, которая и будет интересовать нас больше всего. Здесь уже есть несколько файлов — это демонстрационное приложение от создателей Nest.js.

Самое приятное, что приложение уже рабочее и его можно запустить. Делается это при помощи команды

npm run start:dev

Теперь, если ввести в адресную строку браузера http://localhost:3000, то мы увидим возвращённую сервером фразу Hello world!.

Запущенное командой npm run start:dev приложение будет перезагружаться каждый раз, когда изменяется исходный код проекта.

Остановить работающее приложение можно комбинацией клавиш Ctrl+C.

Точка входа

Точкой входа в приложение на Nest.js, как и в любом другом MVC-подобном фреймворке, являются контроллеры. Пока в приложении имеется один: app.controller.ts:

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

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

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

Обратите внимание, что класс AppController и метод getHello() помечены декораторами @Controller() и @Get(). Nest.js очень широко использует декораторы, поэтому к ним лучше сразу привыкать. Они позволяют писать приложение в более декларативном ключе, указывая что мы хотим сделать, и оставляя детали реализации фреймворку.

Если читатель «плавает» в теме декораторов, рекомендуем к прочтению эту статью.

Декоратор @Get() говорит, что когда в приложение придёт HTTP-запрос методом GET на роут '/' (это значение по умолчанию, поэтому его можно не указывать), его следует направить в метод getHello().

Соответственно, значение, которое вернётся из метода, будет отправлено в теле ответа. Код ответа по умолчанию для GET-запросов — 200.

Метод getHello() и конструктор мы пока удалим. Взамен создадим метод index(), который будет возвращать статьи. Контроллер приобретёт такой вид:

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

@Controller()
export class AppController {
  @Get()
  index() {
    return { articles: [] };
  }
}

Теперь, зайдя на http://localhost:3000 мы вместо Hello world увидим такой JSON:

{
  "articles": []
}

Обратите внимание, что мы возвращаем не «голый» массив, а заворачиваем его в объект c ключом articles. Нам это пригодится чуть дальше.

Статьи

Пришло время наполнить блог статьями. Но что такое «статья»? Каждая статья — объект, который будет иметь уникальный идентификатор, заголовок и контент.

Создадим в папке src новый файл article.model.ts и в нём опишем класс статьи:

export class Article {
  id: number;

  title: string;

  content: string;

  constructor (title: string, content: string, id?: number) {
    this.id = id;
    this.title = title;
    this.content = content;
  }
}

Почему id — необязательный параметр, выяснится позже — когда будем подключать базу данных.

Теперь представим, что у нас в блоге уже есть парочка статей. Создадим файл articles.ts:

import { Article } from './article.model';

export const articles: Article[] = [
 new Article('The first one', 'Lorem ipsum ....', 1),
 new Article('The second one', 'Lorem ipsum ....', 2)
]

Осталось вернуть массив статей из метода index() в контроллере:

import { articles } from './articles';

@Controller()
export class AppController {
  @Get()
  index() {
    return { articles };
  }
}

Если теперь запустить приложение, мы увидим в браузере следующее:

{
  "articles": [
    {
      "id": 1,
      "title": "The first one",
      "content": "Lorem ipsum ...."
    },
    {
      "id": 2,
      "title": "The second one",
      "content": "Lorem ipsum ...."
    }
  ]
}

Добавляем HTML-шаблоны

Для того, чтобы пользователю было комфортнее работать с сайтом, сервер должен вернуть браузеру ответ не в формате json, а в виде html-страницы.

Создадим в корне проекта директорию views — в ней мы будем размещать HTML-шаблоны.

Устанавливаем шаблонизатор

Nest.js по умолчанию не устанавливает никаких движков шаблонизации, так как не знает, какой именно по душе пользователю. Мы для этого примера возьмём pug (ранее известный как jade). Этот пакет нам придется установить самостоятельно:

npm install pug

Чтобы подключить pug, перепишем функцию bootstrap (main.ts):

import { join } from 'path';
import { NestExpressApplication } from '@nestjs/platform-express';

async function bootstrap() {
  /*
  * Добавим параметр типа к методу create, показывая, что мы хотим работать
  * с объектом app, как с приложением express.
  */
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  // Сообщим приложению, где искать наши views.
  app.setBaseViewsDir(join(__dirname, '../views'));

  // И укажем, какой шаблонизатор использовать
  app.setViewEngine('pug');
  await app.listen(3000);
}

Первый шаблон

Наш первый шаблон index.pug будет выглядеть так:

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(http-equiv="X-UA-Compatible", content="IE=edge")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title SuperBlog!
  body
    h1 Welcome to SuperBlog!
    // Конструкция "each" позволяет перебрать массив и для каждого элемента сгенерировать разметку
    ul
      each article in articles
        // #{...} — интерполяция. Так шаблонизатор понимает, что сюда надо встроить данные.
        li #{article.title}  <a href="...">Читать</a>

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

В контроллере добавим к методу index декоратор @Render() (импортируется из пакета @nestjs/common):

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

@Controller()
export class AppController {
  @Get()
  @Render('index')
  index() {
    return { articles };
  }
}

@Render('index') указывает фреймворку, что те данные, которые возвращаются из метода нужно не просто вернуть браузеру, а использовать для отрисовки шаблона с названием index (расширение не важно).

Готово. Теперь при запуске приложения мы увидим то, что и ожидали — html-страницу с двумя статьями.

Читайте также: Что такое webpack externals и как их настроить.

Добавляем просмотр статей

В app.controller.ts добавим в импорт декоратор @Param() и создадим новый метод:

import { Render, Param, ParseIntPipe } from '@nestjs/common';

...
@Get(':id')
@Render('article')
getById(@Param('id', ParseIntPipe) id: number) {
  return articles.find(article => article.id === id);
}

Строка :id в декораторе @Get() означает, что в этот метод будут направлены запросы на корневой роут с параметром, например: GET http://localhost/1.

При помощи декоратора @Param() мы можем достать этот идентификатор из URL, преобразовать его к числу (ParseIntPipe) и использовать для поиска нужной статьи.

Кроме декоратора @Param() в Nest.js есть также декораторы @Query() для query-параметров и @Body() для тела запроса.

Добавим в папку views шаблон article.pug:

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(http-equiv="X-UA-Compatible", content="IE=edge")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title #{title}
  style
  body
    h1 #{title}
    p #{content}
    a(href="/") Назад

Шапка будет та же самая, только в тэге title мы выведем название статьи. В теле страницы — ожидаемо title и content, а также ссылка «назад» — на главную страницу.

Осталось починить ссылки на главной странице:

li #{article.title} 
  a(href=article.id) Читать

Теперь, зайдя на главную страницу, можно кликнуть по ссылке «Читать» у любой из статей и увидеть содержимое статьи. А при клике на «Назад» — вернуться к списку статей. Также можно зайти на страницу по прямой ссылке, например http://localhost:3000/1.

Добавляем статью

Чтобы создать новую статью, браузер должен отправить на сервер title и content POST-запросом. Чтобы реализовать это, добавим в контроллер перед методом article два новых метода:

import { Body, Post, Redirect } from '@nestjs/common';
import { Article } from './article.model';

@Get('create')
@Render('create-article')
getForm(): void {
  return;
}

@Post('articles')
@Redirect('/', 301)
create(@Body() body: any): void {
  const id = articles.length + 1;
  const article = new Article(body.title, body.content, id);
  articles.push(article);
}

Метод getForm() не требует никакого возвращаемого значения — он просто возвращает статический HTML.

В методе create() реализуем добавление статьи в коллекцию. Думаю, читатель уже догадался, что декоратор @Post() означает одноимённый HTTP-глагол. Декоратор @Body() указывает фреймворку, что данные для параметра нужно брать из тела запроса. И, наконец, декоратор @Redirect(‘/’, 301) говорит, что после добавления статьи требуется переадресовать пользователя. Первый аргумент - ‘/’ обозначает корневой роут (то есть, главную страницу), а 301 — код ответа.

Шаблон create-article.pug будет выглядеть так:

doctype html
html
  head
    title Новая статья
  style
  body
    h1 Новая статья
    form(method="POST" action="/articles")
      input(type="text" name="title")
      input(type="text" name="content")
      button(type="submit") Создать

Добавление статей реализовано. На страницу добавления можно попасть, введя в адресной строке http://localhost:3000/create. Чтобы было чуть удобнее, добавим ссылку на эту страничку вниз списка статей. index.pug приобретёт такой вид:

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(http-equiv="X-UA-Compatible", content="IE=edge")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title SuperBlog!
  body
    h1 Welcome to SuperBlog!
    ul
      each article in articles
        li #{article.title} 
          a(href=article.id) Читать
    a(href="create") Создать

Заключение

Nest.js позволяет нам написать простое приложение с минимальными усилиями. Однако истинная мощь фреймворка станет очевидна при более глубоком погружении. Среди особенно мощных возможностей, выделяющих его на фоне других:

  • Декларативное программирование при помощи декораторов
  • Встроенный DI-контейнер (кратко о DI и IoC)
  • Мощные специализированные middleware: интерцепторы, пайпы, гарды
  • Механизм обработки ошибок «из коробки»
  • Поддержка любых протоколов, помимо HTTP. На Nest.js можно писать сервисы на основе RabbitMQ, Nats, Kafka или даже просто TCP-протокола.

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

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

Node.js-разработчик — с нуля до трудоустройства за 10 месяцев
  • Постоянная поддержка от наставника и учебного центра
  • Помощь с трудоустройством
  • Готовое портфолио к концу обучения
  • Практика с первого урока

Вы получите именно те инструменты и навыки, которые позволят вам найти работу

Узнать больше

Аватар пользователя Eonae
Eonae 07 июля 2022
23
Похожие статьи
Рекомендуемые программы
профессия
Верстка на HTML5 и CSS3, Программирование на JavaScript в браузере, разработка клиентских приложений используя React
10 месяцев
с нуля
Старт 26 декабря
профессия
Программирование на Python, Разработка веб-приложений и сервисов используя Django, проектирование и реализация REST API
10 месяцев
с нуля
Старт 26 декабря
профессия
Тестирование веб-приложений, чек-листы и тест-кейсы, этапы тестирования, DevTools, Postman, SQL, Git, HTTP/HTTPS, API
4 месяца
с нуля
Старт 26 декабря
профессия
Программирование на Java, Разработка веб-приложений и микросервисов используя Spring Boot, проектирование REST API
10 месяцев
с нуля
Старт 26 декабря
профессия
новый
Google таблицы, SQL, Python, Superset, Tableau, Pandas, визуализация данных, Anaconda, Jupyter Notebook, A/B-тесты, ROI
9 месяцев
с нуля
Старт 26 декабря
профессия
Программирование на PHP, Разработка веб-приложений и сервисов используя Laravel, проектирование и реализация REST API
10 месяцев
с нуля
Старт 26 декабря
профессия
Программирование на Ruby, Разработка веб-приложений и сервисов используя Rails, проектирование и реализация REST API
5 месяцев
c опытом
Старт 26 декабря
профессия
Программирование на JavaScript в браузере и на сервере (Node.js), разработка бекендов на Fastify и фронтенда на React
16 месяцев
с нуля
Старт 26 декабря
профессия
Программирование на JavaScript, разработка веб-приложений, bff и сервисов используя Fastify, проектирование REST API
10 месяцев
с нуля
Старт 26 декабря
профессия
новый
Git, JavaScript, Playwright, бэкенд-тесты, юнит-тесты, API-тесты, UI-тесты, Github Actions, HTTP/HTTPS, API, Docker, SQL
8 месяцев
c опытом
Старт 26 декабря