Как построить GraphQL API с помощью Nest.js?
В этой статье вы узнаете, как создать GraphQL API с помощью NestJS, используя преимущества его чистой архитектуры и безопасности типов.
NestJS – это фреймворк NodeJS, который помогает пользователям создавать масштабируемые внутренние приложения корпоративного уровня, обеспечивая безопасность типов и строгую архитектурную модель.
GraphQL – это язык запросов для интерфейсов прикладного программирования (API), широко используемый в качестве альтернативы REST благодаря своей скорости и стабильности, которые достигаются за счет того, что в ответ на запросы поступают именно те данные, которые они запрашивают. Эта особенность GraphQL решает проблему перевыборки и недовыборки, которую создает REST.
Contents
- 1 Настройка среды разработки
- 2 Создание сущности
- 3 Создание типа объекта
- 4 Создание службы
- 5 Создание резольвера
- 6 Тестирование вашего API с помощью GraphQL Playground
- 7 Back4app и GraphQL
- 8 Заключение
- 9 ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
- 10 Что такое GraphQL?
- 11 Что такое Nest.JS?
- 12 Как создать API GraphQL с помощью Nest.JS?
Настройка среды разработки
Если 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
Далее вы увидите игровую площадку, на которой можно протестировать запросы и мутации, как показано на рисунке ниже.
Чтобы получить все блоги из базы данных, выполните следующий запрос:
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,
}
}
Пример показан на изображении ниже:
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
– Подключение к базе данных
– Создание ресурсов
– Создание сущности
– Создание типа объекта
– Создание службы