Как построить GraphQL API с помощью Nest.js?

В этой статье вы узнаете, как создать GraphQL API с помощью NestJS, используя преимущества его чистой архитектуры и безопасности типов.

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

GraphQL – это язык запросов для интерфейсов прикладного программирования (API), широко используемый в качестве альтернативы REST благодаря своей скорости и стабильности, которые достигаются за счет того, что в ответ на запросы поступают именно те данные, которые они запрашивают. Эта особенность GraphQL решает проблему перевыборки и недовыборки, которую создает REST.

Настройка среды разработки

Если Nest.js CLI еще не установлен в вашей системе, выполните следующую команду для его установки:

npm i -g @nestjs/cli

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

Затем создайте проект и сгенерируйте необходимые стартовые файлы, выполнив приведенную ниже команду:

nest new graphql-api

Затем выполните приведенную ниже команду, чтобы перейти в каталог проекта:

cd graphql-api

Затем установите необходимые зависимости, выполнив приведенную ниже команду:

npm i @nestjs/graphql @nestjs/apollo graphql apollo-server-express

Установленные выше зависимости включают:

  • nest/graphql
  • nestjs/apollo
  • graphql
  • apollo-server-express

Затем установите пакет TypeORM и драйвер базы данных sqlite, выполнив следующую команду:

npm install @nestjs/typeorm typeorm sqlite3

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

Настройка GraphQL в Nest.js

Nest.js предлагает два способа создания GraphQL API: код-первый и схема-первый подходы.

Подход code-first предусматривает использование декораторов и классов TypeScript для генерации соответствующей схемы GraphQL.

Подход, основанный на схеме, предполагает использование файлов GraphQL Schema Definition Language (SDL), а Nest.js генерирует определения TypeScript с помощью классов или интерфейсов, основанных на схеме GraphQL Schema.

В этом уроке мы рассмотрим использование подхода code-first, чтобы избежать переключения контекста между разными языками.

Чтобы использовать подход “код сначала”, перейдите в начальный файл вашего приложения, app.module.ts, и импортируйте GraphQLModule из @nestjs/graphql. Например:

import { GraphQLModule } from '@nestjs/graphql';

Затем в массиве imports вызовите метод GraphQLModule forRoot. Этот метод принимает в качестве аргумента объект конфигурации. Параметры конфигурации передаются через базовый драйвер GraphQL (в данном руководстве используется драйвер Apollo). Установите свойство autoSchemaFile в объекте конфигурации на schema.gql. Например:

//app.module.ts
GraphQLModule.forRoot({ autoSchemaFile: 'schema.gql' }),

Свойство autoSchemaFile – это путь к файлу, в котором будет храниться автоматически сгенерированная схема.

Подключение к базе данных

Чтобы подключить приложение к базе данных, перейдите в файл app.module.ts и импортируйте TypeOrmModule из @nestjs/typeorm.

Например, так:

import { TypeOrmModule } from '@nestjs/typeorm';

Затем добавьте приведенный ниже блок кода в массив imports:

TypeOrmModule.forRoot({
      type: 'sqlite',
      database: ':memory:',
      entities: ['dist/**/*.entity{.ts,.js}'],
      synchronize: true,
    }),

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

Генерация ресурсов

Затем создайте модуль для организации кода, выполнив следующую команду:

nest g module blog

Приведенная выше команда генерирует модуль блога для вашего приложения.

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

nest g service blog

В приведенном выше блоке кода создается и регистрируется служба в вашем приложении. Этот сервис будет содержать и обрабатывать всю бизнес-логику вашего приложения.

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

nest g resolver

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

Создание сущности

Сущность – это набор полей, определяющих способ хранения данных в базе данных.

Чтобы создать сущность, в папке вашего модуля (blog) создайте файл сущности, следуя соглашению .entity.ts, например, blog.entity.ts.

В файле сущности импортируйте Column, Entity и PrimaryGeneratedColumn из typeorm. Например:

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

Декоратор Column добавляет поля, которые он аннотирует как столбцы в базе данных. Декоратор Entity помечает аннотируемый класс как сущность. Декоратор PrimaryGeneratedColumn отмечает свойство, которое аннотирует, как уникальный идентификатор вашей таблицы и автоматически генерирует его.

Далее создайте и экспортируйте класс Blog. Затем аннотируйте класс декоратором Entity, чтобы обозначить его как сущность. Например:

@Entity()
export class Blog {}

Поскольку в этом учебнике используется API блога, добавьте в свой класс свойства id, title, body, author и date. Затем аннотируйте каждое из свойств декоратором Column, кроме свойства id. Аннотируйте свойство id декоратором PrimaryGeneratedColumn.

Например, так:

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

@Entity()
export class Blog {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column()
  body: string;

  @Column()
  author: string;

  @Column()
  date: string;
}

Создание типа объекта

Тип объекта – это определение схемы GraphQL, представляющее объект, с которым должен взаимодействовать клиент. Например, если вы создаете API для блога, вам нужно определить схему/сущность блога с помощью класса TypeScript и аннотировать каждое поле соответствующими декораторами.

Далее в файле сущности импортируйте тип Int и декораторы Field и ObjectType из @nestjs/graphql. Например:

import { Field, Int, ObjectType } from '@nestjs/graphql';

Декоратор Field отмечает определенное свойство класса как поле GraphQL. Только свойства, аннотированные этим декоратором, будут определены в схеме. В качестве аргументов он принимает необязательную функцию возвращаемого типа и объект конфигурации.

Тип Int необходим, чтобы устранить потенциальную двусмысленность между системами типов TypeScript и GraphQL. Он требуется только для свойств с числовыми значениями, поскольку они могут быть либо целыми числами, либо float.

Декоратор ObjectType отмечает класс как тип GraphQL.

Затем аннотируйте свой класс Blog декоратором ObjectType, чтобы обозначить его как тип GraphQL. Например:

@ObjectType()
export class Blog {}

Наконец, укажите необходимые свойства вашего типа внутри класса и аннотируйте каждое из них с помощью декоратора Field. Например:

//blog.entity.ts
import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
@ObjectType()
export class Blog {
  @PrimaryGeneratedColumn()
  @Field((type) => Int)
  id: number;

  @Column()
  @Field()
  title: string;

  @Column()
  @Field()
  body: string;

  @Column()
  @Field()
  author: string;

  @Column()
  @Field()
  date: string;
}

Ваш готовый тип объекта должен выглядеть так, как показано в блоке кода выше.

Обратите внимание, что в приведенном выше блоке кода идентификатор с типом число был явно указан как целое число, чтобы избежать двусмысленности между системами типов TypeScript и GraphQL.

Наконец, внедрите сущность в ваше приложение, чтобы создать уровень доступа между вашим приложением и базой данных.

Для этого перейдите в файл blog.module.ts, импортируйте TypeOrmModule из @nestjs/typeorm и импортируйте сущность Blog.

Затем добавьте приведенный ниже блок кода в декоратор модуля:

imports: [TypeOrmModule.forFeature([Blog])],

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

Создание службы

Перейдите в ранее созданный файл сервиса blog.service.ts и импортируйте InjectRepository из @nestjs/typeorm, а также тип вашего объекта.

Например, так:

import { InjectRepository } from '@nestjs/typeorm';
import { Blog } from './blog.entity';

Затем добавьте приведенный ниже блок кода в класс BlogService для инъекции репозитория:

constructor(
    @InjectRepository(Blog)
    private blogRepository: Repository<Blog>,
  ) {}

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

async getAll(): Promise<Blog[]> {
    return await this.blogRepository.find();
  }

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

Создание типа ввода

Чтобы создать тип ввода для мутаций, которые принимают сложные объекты, создайте папку dtos в папке блога. Затем в папке dtos создайте новый файл create-blog.input.ts.

В файле create-blog.input.ts импортируйте декораторы Field и InputType. Например:

import { Field, InputType } from '@nestjs/graphql';

Декоратор InputType отмечает класс как тип ввода GraphQL.

Далее создайте и экспортируйте класс BlogInput. Затем аннотируйте класс декоратором InputType. Например:

@InputType()
export class BlogInput {}

Наконец, добавьте все необходимые свойства блога и аннотируйте их с помощью декоратора Field.

Например, так:

//create-blog.input.ts
import { Field, InputType } from '@nestjs/graphql';

@InputType()
export class BlogInput {
  @Field()
  id: number;

  @Field()
  title: string;

  @Field()
  body: string;

  @Field()
  author: string;

  @Field()
  date: string;
}

Ваш готовый тип ввода должен выглядеть так, как показано в блоке кода выше.

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

async createBlog(blogInput: BlogInput): Promise<Blog> {
    const newBlog = this.blogRepository.create(blogInput);

    return this.blogRepository.save(newBlog);
  }

Тип input применяется так же, как и обычный объект передачи данных Nest.js, в качестве механизма проверки входящих данных. Как и в случае с dtos, вы можете выполнить дополнительную проверку данных с помощью пакета class-validator.

Создание резольвера

Перейдите к ранее созданному файлу Resolver, blog.resolver.ts, и импортируйте сущность, тип ввода и сервис. Например:

import { Blog } from './blog.entity';
import { BlogService } from './blog.service';
import { BlogInput } from './dto/create-blog.input';

Затем добавьте приведенный ниже блок кода в класс Resolver, чтобы внедрить службу в ваш резольвер:

constructor(private blogService: BlogService) {}

Далее импортируйте декораторы Args, Mutation и Query из @nestjs/graphql.

Например, так:

import { Args, Mutation, Query } from '@nestjs/graphql';

Декоратор Args извлекает объект arguments из базовой платформы и заполняет декорированный параметр значением всех аргументов или одного указанного аргумента.

Декоратор Mutation определяет маршрут как мутацию.

Декоратор Query задает маршрут в виде запроса.

Затем передайте приведенную ниже функцию в декоратор Resolver, чтобы указать тип объекта:

(of) => Blog

Затем добавьте приведенный ниже блок кода в класс Resolver, чтобы разрешить метод getAll.

 @Query((type) => [Blog])
  async getAllBlogs() {
    return this.blogService.getAll();
  }

Наконец, добавьте приведенный ниже блок кода в класс Resolver, чтобы разрешить метод createBlog.

 @Mutation((returns) => Blog)
  createBlog(@Args('blogInput') blogInput: BlogInput): Promise<Blog> {
    return this.blogService.createBlog(blogInput);
  }

Примечание: Обязательно укажите функцию возвращаемого типа для каждого декоратора.

Ваш готовый класс Resolver должен выглядеть так, как показано в блоке кода ниже:

@Resolver((of) => Blog)
export class BlogResolver {
  constructor(private blogService: BlogService) {}

  @Query((type) => [Blog])
  async getAllBlogs() {
    return this.blogService.getAll();
  }

  @Mutation((returns) => Blog)
  createBlog(@Args('blogInput') blogInput: BlogInput): Promise<Blog> {
    return this.blogService.createBlog(blogInput);
  }
}

Тестирование вашего API с помощью GraphQL Playground

Чтобы протестировать приложение с помощью игровой площадки GraphQL, доступной по умолчанию, выполните приведенную ниже команду и перейдите по адресу http://localhost:3000/graphql.

npm start

Далее вы увидите игровую площадку, на которой можно протестировать запросы и мутации, как показано на рисунке ниже.

Игровая площадка GraphQL

Чтобы получить все блоги из базы данных, выполните следующий запрос:

query getAll{
  getAllBlogs {
    id,
    title,
    body,
    author,
    date
  }
}

Пример показан на изображении ниже:

Чтобы добавить блог в свою базу данных, выполните приведенную ниже мутацию:

mutation createBlog {
  createBlog (blogInput: {
    id: 1, 
    title: "GraphQL is great", 
    body: "GraphQL APIs are faster than REST APIs", 
    author: "David Ekete",
    date: "01-02-03"
  }) {
    id,
    title,
    body,
    author,
    date,
  }
}

Пример показан на изображении ниже:

Игровая площадка GraphQL

Back4app и GraphQL

Благодаря многочисленным преимуществам GraphQL по сравнению с REST, таким как контроль получения данных, платформа Back4app предоставляет GraphQL API, интегрированный в ваши приложения для разбора, работающие на платформе.

Эта интеграция позволяет вам проверять работоспособность бэкенда вашего сервера, выполнять операции Create, Read, Update, Delete (CRUD) над базой данных и многое другое с помощью простых GraphQL-запросов и мутаций.

Например, чтобы проверить состояние бэкэнд-сервера с помощью GraphQL API, выполните следующий запрос:

query Health {
  health
}

Приведенный выше запрос вернется:

{
  "data": {
    "health": true
  }
}

Чтобы начать работу с функцией GraphQL, перейдите на приборную панель Parse, выберите и щелкните свое приложение. В пользовательском интерфейсе приложения выберите и нажмите Core, затем выберите и нажмите API console и выберите GraphQL console.

Следуя приведенным выше инструкциям, вы откроете консоль GraphQL, в которой можно выполнять запросы и мутации, аналогичные той игровой площадке GraphQL, которую вы использовали при разработке. Вы можете узнать больше о функции GraphQL от Back4app в документации Back4app.

Заключение

В этой статье мы рассмотрели, как создать GraphQL API в Nest.js и протестировать API с помощью GraphQL playground. API GraphQL имеют ряд преимуществ перед API REST.

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

Независимо от вашего выбора, GraphQL или REST, вам все равно придется развернуть приложение. Back4app – это low-code BaaS, основанный на технологиях с открытым исходным кодом, который упрощает процесс создания бэкенда, устраняя повторяющиеся задачи с помощью многократно используемых шаблонов и управляя большей частью инфраструктуры бэкенда.

Среди особенностей Back4app – база данных в реальном времени, облачные функции, нативные API и SDK, полная система управления пользователями и многое другое.

Эта платформа также имеет бесплатный уровень, который позволяет вам изучить платформу без оплаты.

Счастливого строительства!

ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ

Что такое GraphQL?

GraphQL — это язык запросов и обработки данных с открытым исходным кодом для API, созданный Facebook в 2012 году.

Что такое Nest.JS?

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

Как создать API GraphQL с помощью Nest.JS?

– Настройка GraphQL в Nest.js
– Подключение к базе данных
– Создание ресурсов
– Создание сущности
– Создание типа объекта
– Создание службы


Leave a reply

Your email address will not be published.