Как построить приложение NestJS MVC с YugabyteDB

Эта статья является второй в серии постов, посвященных способам создания приложений с помощью NestJS. В первой части мы создали приложение для двухфакторной аутентификации с помощью NestJS.

Построение двухфакторной аутентификации с помощью NestJS и Postgres

Arctype Team for Arctype ・ Jan 28 ・ 13 min read

#postgres #nestjs #softwaredevelopment #technology

В этой статье мы узнаем больше об архитектуре контроллера представления модели (MVC), создав приложение NestJS MVC с YugabyteDB. Мы создадим демонстрационный проект магазина электронных книг. Код для этого руководства доступен в моем репозитории Github. Не стесняйтесь клонировать его по мере выполнения шагов. Давайте начнем!

Проектирование контроллера представления модели

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

Три логических компонента MVC выглядят следующим образом:

  • Модель: По сравнению с View и Controller, этот уровень считается самым низким. Он представляет собой данные, которые передаются между компонентами View и Controller, и определяет хранение всех элементов данных в приложении.
  • Представление: Этот компонент отвечает за пользовательский интерфейс приложения. Он также управляет данными конечного пользователя, а также связью между пользователем и контроллером.
  • Контроллер: Контроллер завершает цикл, получая пользовательский ввод, преобразуя его в соответствующие сообщения, передавая их представлениям и управляя обработчиками запросов.

Модель MVC имеет следующие преимущества:

  • Он позволяет легко организовывать большие веб-приложения
  • Он позволяет легко изменять любую часть приложения, не затрагивая при этом другие части приложения
  • Упрощает процесс тестирования кода
  • Позволяет легко сотрудничать между командами разработчиков
  • Это помогает разработчикам создавать легко поддерживаемый код
  • Позволяет разработчикам создавать и использовать предпочитаемые ими движки представления.

Предварительные условия

Этот учебник представляет собой практическую демонстрацию. Чтобы следовать этому руководству, убедитесь, что у вас установлено следующее:

  • Arctype
  • NodeJS
  • База данных Yugabyte
  • Postman

Код для этого руководства доступен в моем репозитории Github. Не стесняйтесь клонировать его по мере выполнения шагов.

Что такое NestJS?

NestJS — это фреймворк Node.js для создания быстрых, тестируемых, масштабируемых, слабосвязанных серверных приложений, использующих TypeScript. Он использует преимущества мощных серверных HTTP-фреймворков, таких как Express или Fastify. Nest добавляет уровень абстракции к фреймворкам Node.js и раскрывает их API для разработчиков. Он поддерживает такие системы управления базами данных, как PostgreSQL, MySQL, а в этом учебнике — yugabyteDB. NestJS также предлагает инъекции зависимостей из коробки.

Почему стоит использовать NestJS?

NestJS является одним из самых популярных фреймворков Node.JS с момента его выхода в 2017 году. Некоторые из причин, по которым разработчики используют NestJS, следующие:

  • Он обладает высокой масштабируемостью и прост в обслуживании
  • У него большое сообщество разработчиков и система поддержки
  • Nest нашел уникальное пересечение front-end и middleware программирования, которое многие языки пытаются обнаружить.
  • Поддержка TypeScript в NestJS гарантирует, что он останется актуальным в постоянно развивающемся мире JavaScript и обеспечит разработчикам меньше контекстных сдвигов.
  • Имеет исчерпывающую документацию
  • Простое модульное тестирование
  • Он создан для крупномасштабных корпоративных приложений
  • Nest предоставляет готовую архитектуру приложений, которая позволяет разработчикам и командам создавать высокотестируемые, масштабируемые, слабосвязанные и легко поддерживаемые приложения.

Настройка проекта

Прежде чем мы погрузимся в кодинг, давайте создадим наш проект NestJS и определим структуру проекта. Начнем с создания папки проекта. Откройте терминал и выполните следующую команду:

mkdir nestmvcapp && cd nestmvcapp
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем установите NestJS CLI с помощью следующей команды:

npm i -g @nestjs/cli
Войти в полноэкранный режим Выйти из полноэкранного режима

После завершения установки выполните приведенную ниже команду для создания проекта NestJS.

nest new bookapi
Войти в полноэкранный режим Выйти из полноэкранного режима

Выберите предпочтительный менеджер пакетов npm. Для этого руководства мы будем использовать npm и подождем, пока необходимые пакеты будут установлены. После завершения установки перейдем к созданию нашей таблицы базы данных с помощью Arctype.

Настройка базы данных YugabyteDB

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

# Ubuntu 20.04
sudo apt install python-is-python3
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Затем убедитесь, что у вас установлен wget. Это можно сделать с помощью команды ниже.

sudo apt install wget
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Далее загрузите и извлеките базу данных Yugabyte Database:

# download
wget https://downloads.yugabyte.com/releases/2.11.2.0/yugabyte-2.11.2.0-b89-linux-x86_64.tar.gz

# extract
tar xvfz yugabyte-2.11.2.0-b89-linux-x86_64.tar.gz && cd yugabyte-2.11.2.0/
Войдите в полноэкранный режим Выйти из полноэкранного режима

Затем настройте YugabyteDB с помощью приведенной ниже команды.

./bin/post_install.sh
Войти в полноэкранный режим Выйти из полноэкранного режима

Наконец, запустите вашу базу данных Yugabyte.

./bin/yugabyted start
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь подключим Arctype к Yugabyte. Откройте Arctype, перейдите на вкладку YugabyteDB и подключитесь к базе данных Yugabyte, заполнив информацию, как показано на скриншоте ниже:

Обратите внимание, что на скриншоте выше мы оставили вход базы данных пустым. Это потому, что у нас еще нет ни одной созданной базы данных. Итак, давайте создадим одну. Нажмите на кнопку New Query (Новый запрос) и выполните приведенную ниже команду SQL:

CREATE DATABASE books_db;
Войти в полноэкранный режим Выйти из полноэкранного режима

Установка зависимостей

Когда наша база данных Yugabyte настроена, давайте установим зависимости для нашего приложения. Установите typeorm, pg и ejs с помощью команды ниже:

npm install --save @nestjs/typeorm typeorm pg ejs
Войти в полноэкранный режим Выйти из полноэкранного режима

Установка займет немного времени, поэтому подождите, пока она завершится. Затем мы можем приступить к созданию нашего приложения.

Создайте модуль Books

Модуль — это класс, аннотированный декоратором @Module(). Nest использует метаданные, предоставляемые декоратором @Module(), для организации структуры приложения. Мы создадим модуль books с помощью команды ниже:

nest generate module books
Войти в полноэкранный режим Выйти из полноэкранного режима

Приведенная выше команда создаст папку books в папке src с файлом books.module.ts и зарегистрирует его в файле корневого модуля приложения (app.module.ts).

Создание класса модели Books

Создав модуль books, давайте создадим модель для создания и чтения данных из нашей базы данных.

Создайте класс модели книги с помощью команды ниже:

nest generate class /books/model/book --flat
Войти в полноэкранный режим Выйти из полноэкранного режима

Приведенная выше команда создаст файл model/book.ts в каталоге модуля books. Флаг —flat гарантирует, что Nest не будет генерировать папку для модели books.

Далее давайте определим нашу модель базы данных с помощью Typeorm. Нам нужны поля id, title, author, quantity, description и createdAt для нашей модели книг. Мы будем использовать декоратор Typeorm Entity для определения класса нашей модели, декоратор Column для определения полей, PrimaryGeneratedColumn для создания случайных идентификаторов для наших книг с помощью uuid, и декоратор CreatedDateColumn для сохранения текущей даты-времени, когда книга была создана. Откройте файл model/book.ts и добавьте приведенный ниже фрагмент кода:

import { Entity, Column, PrimaryGeneratedColumn, PrimaryColumn, CreateDateColumn } from 'typeorm';

@Entity()
export class Book {

   @PrimaryGeneratedColumn("uuid")
   id: number;

   @Column()
   title: string;

   @Column()
   author: string;

   @Column()
   quantity: number

   @Column()
   description: String

   @CreateDateColumn()
   createdAt: Date;
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Когда мы запустим наше приложение, Typeorm сгенерирует SQL-эквивалент модели, чтобы создать таблицу книг в нашей базе данных Yugabyte.

Далее мы подключим наше приложение к базе данных Yugabyte в файле src/app.module.ts. Сначала импортируйте модуль Nest TypeOrmModule и класс модели Books с помощью приведенного ниже фрагмента кода:

import { TypeOrmModule } from '@nestjs/typeorm'
import { Book } from './movie/model/book';
Вход в полноэкранный режим Выйти из полноэкранного режима

Затем подключитесь к базе данных с помощью метода forRoot с нашими учетными данными базы данных с помощью приведенного ниже фрагмента кода:

imports: [
   …
   TypeOrmModule.forRoot({
     type: 'postgres',
     host: 'localhost',
     username: 'yugabyte',
     port: 5433,
     password: '',
     database: 'books_db',
     entities: [Book],
     synchronize: true,
   }),
 ],
Войти в полноэкранный режим Выход из полноэкранного режима

Нам также необходимо экспортировать наш класс модели Books в файле books.module.ts, чтобы сделать его доступным. Сначала мы импортируем модуль TypeOrmModule и класс модели Books.

import { TypeOrmModule } from '@nestjs/typeorm';
import { Book } from './model/book';
Вход в полноэкранный режим Выход из полноэкранного режима

Затем мы сделаем класс модели Book доступным с помощью метода TypeOrmModule forFeature.

…
@Module({
 imports: [TypeOrmModule.forFeature([Book])],
 …
Вход в полноэкранный режим Выход из полноэкранного режима

Создание представлений

Когда наша модель книги определена, давайте создадим представление для нашего приложения. Создайте папку Views в каталоге модуля books. Мы создадим шаблоны представлений для нашего приложения и будем использовать ejs, который мы установили в предыдущем разделе, в качестве шаблонизатора. Чтобы начать работу, давайте удалим шаблонный код в нашем файле main.ts и приведенный ниже код для настройки нашего шаблонизатора и каталога статических файлов.

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
 const app = await NestFactory.create<NestExpressApplication>(
   AppModule,
 );
 app.useStaticAssets(join(__dirname, '..', '/src/public'));
 app.setBaseViewsDir(join(__dirname, '..', '/src/books/views'));
 app.setViewEngine('ejs');

 await app.listen(3000);
}
bootstrap();
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь мы можем создать наши файлы шаблонов. Мы начнем с header.ejs и footer.ejs, которые будут созданы в папке books/views/partials. Затем создадим файлы books.ejs и book-detail.ejs в папке books/views. Откройте шаблон header.ejs и добавьте приведенный ниже фрагмент кода:

<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <!-- Bootstrap CSS -->
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
      crossorigin="anonymous"
    />
    <title>Hello, world!</title>
  </head>
  <body>
    <nav class="navbar navbar-light bg-light">
      <div class="container-fluid">
        <a class="navbar-brand">Book Store</a>
        <% if (page ==="book"){ %>
        <form class="d-flex">
          <input
            class="form-control me-2"
            type="search"
            placeholder="Search"
            aria-label="Search"
          />
          <button class="btn btn-outline-success" type="submit">Search</button>
        </form>
        <button
          type="button"
          class="btn btn-primary"
          data-bs-toggle="modal"
          data-bs-target="#staticBackdrop"
        >
          Add New
        </button>
        <% } %>
      </div>
    </nav>
  </body>
</html>
Вход в полноэкранный режим Выйти из полноэкранного режима

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

Затем откройте шаблон footer.ejs и ссылайтесь на наш файл javascript и CDN bootstrap с помощью приведенного ниже фрагмента кода:

<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"
></script>
<script src="/js/app.js"></script>
</body>
</html>
Вход в полноэкранный режим Выйти из полноэкранного режима

Представления, которые мы создали в шаблонах header.ejs и footer.ejs, будут включены в наши шаблоны books.ejs и book-detail.ejs.

Далее, наши книги будут иметь модальную HTML-форму для добавления новых книг в базу данных, а также список всех книг в нашей базе данных. В шаблоне книг у нас будет форма ввода для отправки запроса на бэкенд для сохранения книги в базе данных. Мы также включим в наш шаблон books шаблоны верхнего и нижнего колонтитулов. Откройте шаблон books.ejs и добавьте приведенный ниже фрагмент кода.

<%- include('partials/header.ejs') %>

<div class="container-fluid mt-3">
 <h4>Book Store</h4>
 <ol class="list-group list-group-numbered">
   <% books.forEach(data=>{ %>

   <li
     class="list-group-item d-flex justify-content-between align-items-start"
   >
     <div class="ms-2 me-auto">
       <div class="fw-bold">
         <a href="book/<%= data.id %>"><%= data.title %></a>
       </div>
     </div>
     <span class="badge bg-primary rounded-pill"><%= data.quantity %></span>
   </li>
   <% }) %>
 </ol>
</div>
<!-- Modal -->
<div
 class="modal fade"
 id="staticBackdrop"
 data-bs-backdrop="static"
 data-bs-keyboard="false"
 tabindex="-1"
 aria-labelledby="staticBackdropLabel"
 aria-hidden="true"
>
 <div class="modal-dialog">
   <div class="modal-content">
     <div class="modal-header">
       <h5 class="modal-title" id="staticBackdropLabel">Add Book</h5>
       <button
         type="button"
         class="btn-close"
         data-bs-dismiss="modal"
         aria-label="Close"
       ></button>
     </div>
     <div class="modal-body">
       <form action="" id="createForm" method="post" action="/movie">
         <div class="mb-3">
           <label for="title" class="form-label">Title</label>
           <input
             required
             type="text"
             class="form-control"
             id="title"
             placeholder="Javascript Cookbook"
             name="title"
           />
         </div>
         <div class="mb-3">
           <label for="author" class="form-label">Author</label>
           <input
             required
             type="text"
             class="form-control"
             id="author"
             name="author"
             placeholder="Nelson Doe"
           />
         </div>
         <div class="mb-3">
           <label for="quantity" class="form-label">Quantity</label>
           <input
             required
             type="number"
             class="form-control"
             id="quantity"
             name="quantity"
             placeholder="40"
           />
         </div>
         <div class="mb-3">
           <label for="description" class="form-label">Description</label>
           <textarea
             class="form-control"
             id="description"
             name="description"
             required
             rows="3"
           ></textarea>
         </div>
         <button type="submit" class="btn btn-primary">Add</button>
       </form>
     </div>
   </div>
 </div>
</div>
<%- include('partials/footer.ejs') %>
Вход в полноэкранный режим Выйти из полноэкранного режима

Шаблон books будет выглядеть так, как показано на скриншоте ниже:

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

Добавьте приведенный ниже фрагмент кода в шаблон book-detail:

<%- include('partials/header.ejs') %>
<div class="container-fluid">
 <table class="table">
   <thead>
     <tr>
       <th scope="col">Item</th>
       <th scope="col">Details</th>
       <th scope="col">Action</th>
     </tr>
   </thead>
   <tbody>
     <tr>
       <td>Title</td>
       <td colspan="2"><%= book.title %></td>
     </tr>
     <tr>
       <td>Author</td>
       <td colspan="2"><%= book.author %></td>
     </tr>
     <tr>
       <td>Quantity</td>
       <td colspan="2"><%= book.quantity %></td>
     </tr>
     <tr>
       <td>Description</td>
       <td colspan="2"><%= book.description %></td>
     </tr>
     <tr>
       <td colspan="2"></td>
       <td>
         <button
           type="button"
           class="btn btn-primary"
           data-bs-toggle="modal"
           data-bs-target="#update"
         >
           Update
         </button>
         <button
           type="button"
           class="btn btn-danger"
           onclick="deleteBook('<%= book.id %>')"
         >
           Delete
         </button>
       </td>
     </tr>
   </tbody>
 </table>
 <div
   class="modal fade"
   id="update"
   data-bs-backdrop="static"
   data-bs-keyboard="false"
   tabindex="-1"
   aria-labelledby="staticBackdropLabel"
   aria-hidden="true"
 >
   <div class="modal-dialog">
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="update">Update Book</h5>
         <button
           type="button"
           class="btn-close"
           data-bs-dismiss="modal"
           aria-label="Close"
         ></button>
       </div>
       <div class="modal-body">
         <div
           class="alert alert-success alert-dismissible fade show"
           role="alert"
           hidden
         >
           <strong>Succcess!</strong> Record Updated!.
           <button
             type="button"
             class="btn-close"
             data-bs-dismiss="alert"
             aria-label="Close"
           ></button>
         </div>
         <form action="" id="form">
           <div class="mb-3">
             <label for="title" class="form-label">Title</label>
             <input
               type="text"
               class="form-control"
               id="title"
               name="title"
               value="<%= book.title %>"
             />
           </div>
           <div class="mb-3">
             <label for="author" class="form-label">Author</label>
             <input
               type="text"
               class="form-control"
               id="author"
               name="author"
               value="<%= book.author %>"
             />
           </div>
           <div class="mb-3">
             <label for="quantity" class="form-label">Quantity</label>
             <input
               type="text"
               class="form-control"
               id="quantity"
               name="quantity"
               value="<%= book.quantity %>"
             />
           </div>
           <div class="mb-3">
             <label for="description" class="form-label">Description</label>
             <textarea
               class="form-control"
               id="description"
               name="description"
               rows="3"
             >
<%= book.description %></textarea
             >
           </div>
           <input type="hidden" class="" name="id" value="<%= book.id %>" />
           <button type="submit" class="btn btn-primary">Add</button>
         </form>
       </div>
     </div>
   </div>
 </div>
</div>

<%- include('partials/footer.ejs') %>
Войти в полноэкранный режим Выйти из полноэкранного режима

Наш шаблон book-detail будет выглядеть так, как показано на скриншоте ниже:

Теперь давайте создадим папку static files для сохранения наших статических файлов (CSS, JS и изображений). В этом учебнике мы создадим только папку JS для нашего кода javascript. Итак, создайте общую папку в каталоге src и создайте файл js/app.js в общей папке. Затем добавьте приведенный ниже фрагмент кода в файл app.js.

function updateBook() {
 const createForm = document.getElementById('form');
 createForm.addEventListener('submit', async (e) => {
   e.preventDefault();
   const id = createForm['id'].value;
   await fetch(`http://localhost:3000/book/${id}`, {
     method: 'Put',
     headers: {
       'Content-Type': 'application/json',
     },
     body: JSON.stringify({
       title: createForm['title'].value,
       author: createForm['author'].value,
       quantity: createForm['quantity'].value,
       description: createForm['description'].value,
     }),
   })
     .then((data) => data.json())
     .then((res) => {
       if (res) {
         document.querySelector('.alert').removeAttribute('hidden');
         setTimeout(() => {
           window.location.reload();
         }, 3000);
       }
     });
 });
}

async function deleteBook(id) {
 console.log(id);
 await fetch(`http://localhost:3000/book/${id}`, {
   method: 'DELETE',
 }).then(() => (window.location.href = '/book'));
}

updateBook();
Вход в полноэкранный режим Выйти из полноэкранного режима

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

Создание контроллера

Приступим к созданию контроллеров. Создайте контроллер Nest с помощью приведенной ниже команды:

nest generate controller /books/controller/book --flat
Войти в полноэкранный режим Выйти из полноэкранного режима

Приведенная выше команда создаст файл controller/book.controller.ts в папке модуля books с некоторым шаблонным кодом. Откройте файл controller/book.controller.ts и импортируйте необходимые декораторы Nest, необходимые для наших маршрутов, импортируйте наш класс модели Book и класс BookService, который мы создадим позже. Затем создайте метод конструктора BookController и свяжите наш класс BookService, чтобы сделать его доступным в других методах.

import { Controller, Render, Get, Post, Put, Delete, Param, Body, Res } from '@nestjs/common';
import { Book } from '../model/book';
import { BookService } from '../service/book.service'

@Controller('book')
export class BookController {
   constructor(private readonly bookService: BookService) {}
...
Вход в полноэкранный режим Выход из полноэкранного режима

Далее мы создадим наш маршрут allBook, который будет слушать GET-запрос, для рендеринга нашего шаблона книги с помощью декоратора @Render со списком книг из базы данных с помощью фрагмента кода ниже:

…
@Get()
   @Render('book')
   async allBook(): Promise<object> {
       const books = await this.bookService.getAllBook();
       return { books, page: "book" }
   }
…
Вход в полноэкранный режим Выход из полноэкранного режима

Далее мы создадим наш маршрут createBook. Мы используем декоратор @Body для получения входных данных пользователя из тела запроса, при этом данные из тела запроса должны соответствовать схеме книги. Затем мы перенаправим пользователя на ту же страницу с помощью метода перенаправления @Res.

…
@Post()
   async createBook(@Body() book: Book, @Res() res): Promise<any> {
       await this.bookService.createBook(book);
       return res.redirect('/book')
   }
…
Вход в полноэкранный режим Выход из полноэкранного режима

Далее мы создадим маршруты getBook, updateBook и deleteBook. Мы получим идентификатор книги из параметров запроса с помощью декоратора @param, а затем получим, обновим или удалим запись, используя идентификатор. В маршруте updateBook мы также используем декоратор @Body, чтобы получить данные о новой книге из тела запроса.

…
@Get(':id')
   @Render('book-detail')
   async getBook(@Param() params): Promise<object> {
       const book = await this.bookService.getBook(params.id)
       return { book, page: "detail" }
   }
   @Put(':id')
   async updateBook(@Param() params, @Body() book: Book): Promise<Book> {
       return this.bookService.updateBook(params.id, book);
   }

   @Delete(':id')
   async deleteBook(@Param() params): Promise<Book> {
       return this.bookService.deleteBook(params.id)
   }
}
Вход в полноэкранный режим Выход из полноэкранного режима

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

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

nest generate service /books/service/book --flat
Войти в полноэкранный режим Выйти из полноэкранного режима

Приведенная выше команда создаст файл service/book.service.ts в папке нашего модуля books. Теперь давайте создадим наши функции обработчика маршрутов в файле service. Сначала импортируем следующие зависимости:

  • Injectable: Чтобы сделать наш BookService доступным в других файлах нашего проекта.
  • HttpException: Для создания пользовательских HTTP-ошибок
  • HttpStatus: Для отправки пользовательского кода состояния
  • InjectRepository: Для инжектирования нашего класса модели книги в наш BookService.

Мы также импортируем наш класс модели книги. Сделайте это с помощью приведенного ниже фрагмента кода:

import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { Book } from '../model/book';
Вход в полноэкранный режим Выйти из полноэкранного режима

Далее мы добавим метод конструктора в наш класс BookService. Импортируйте нашу модель книги с помощью приведенного ниже фрагмента кода:

...
constructor(@InjectRepository(Book) private readonly bookRepository: Repository<Book>) { }
...
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем мы создадим функции-обработчики getAllBooks и createBooks. Обработчик getAllBooks будет запрашивать у базы данных все книги в базе данных и возвращать их в порядке убывания нашему контроллеру. В то время как обработчик createBook создаст новую книгу с данными объекта book, используя метод save.

…
async getAllBook(): Promise<Book[]> {
       return await this.bookRepository.find({ order: { createdAt: "DESC" } })
   }

   async createBook(book: Book): Promise<Book> {
       return await this.bookRepository.save(book)
   }
…
Вход в полноэкранный режим Выход из полноэкранного режима

Наконец, мы создадим обработчики getBook, updateBook и deleteBook с помощью приведенного ниже фрагмента кода. Эти обработчики будут использовать id книги для получения, обновления или удаления книги из нашей базы данных.

…
async getBook(id: string): Promise<Book> {
       return await this.bookRepository.findOne(id);
   }
   async updateBook(id: string, book: Book): Promise<Book> {
       const updateBook = await this.bookRepository.update(id, book)
       if (!updateBook) {
           throw new HttpException('Book id not found', HttpStatus.NOT_FOUND)
       }
       return await this.bookRepository.findOne(id);
   }
   async deleteBook(id: string): Promise<any> {
       if (await this.bookRepository.delete(id)) {
           return null
       }
       throw new HttpException('Book not found', HttpStatus.NOT_FOUND)
   }
Вход в полноэкранный режим Выход из полноэкранного режима

Заключение

В этом учебнике вы узнали, как построить MVC-приложение NestJS с базой данных Yugabyte, создав демонстрационный проект книжного магазина. Вы узнали, что такое архитектура MVC, как настроить приложение NestJS, а также как настроить и создать базу данных Yugabyte. Для дальнейшего чтения вы также можете прочитать больше о NestJS и YugabyteDB. Для дополнительной сложности вы можете расширить приложение, защитив маршруты удаления и обновления. Что вы будете делать дальше?

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *