Skip to main content
Практика завдань

Як побудувати GraphQL API з NestJS?

GraphQL у NestJS

NestJS надає першокласну підтримку GraphQL через пакет @nestjs/graphql, підтримуючи як code-first, так і schema-first підходи.


Налаштування (Code-First)

bash
npm install @nestjs/graphql @nestjs/apollo @apollo/server graphql
typescript
// app.module.ts import { GraphQLModule } from '@nestjs/graphql'; import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'; @Module({ imports: [ GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, autoSchemaFile: 'schema.gql', // Автоматичне генерування схеми sortSchema: true, playground: true, }), ], }) export class AppModule {}

Об'єктні типи

typescript
import { ObjectType, Field, ID, Int } from '@nestjs/graphql'; @ObjectType() export class User { @Field(() => ID) id: string; @Field() name: string; @Field() email: string; @Field(() => Int) age: number; @Field(() => [Post], { nullable: true }) posts?: Post[]; @Field() createdAt: Date; }

Вхідні типи

typescript
import { InputType, Field } from '@nestjs/graphql'; @InputType() export class CreateUserInput { @Field() @IsString() name: string; @Field() @IsEmail() email: string; @Field(() => Int) @Min(18) age: number; } @InputType() export class UpdateUserInput extends PartialType(CreateUserInput) {}

Розв'язувачі (як Контролери)

typescript
import { Resolver, Query, Mutation, Args, ResolveField, Parent } from '@nestjs/graphql'; @Resolver(() => User) export class UsersResolver { constructor( private usersService: UsersService, private postsService: PostsService, ) {} @Query(() => [User], { name: 'users' }) findAll() { return this.usersService.findAll(); } @Query(() => User, { name: 'user' }) findOne(@Args('id', { type: () => ID }) id: string) { return this.usersService.findOne(id); } @Mutation(() => User) createUser(@Args('input') input: CreateUserInput) { return this.usersService.create(input); } @Mutation(() => User) updateUser( @Args('id', { type: () => ID }) id: string, @Args('input') input: UpdateUserInput, ) { return this.usersService.update(id, input); } @Mutation(() => Boolean) deleteUser(@Args('id', { type: () => ID }) id: string) { return this.usersService.delete(id); } // Вирішення вкладеного поля @ResolveField(() => [Post]) posts(@Parent() user: User) { return this.postsService.findByUserId(user.id); } }

Аутентифікація в GraphQL

typescript
@Resolver(() => User) export class UsersResolver { @Query(() => User) @UseGuards(GqlAuthGuard) me(@CurrentUser() user: User) { return user; } } // GQL Auth Guard @Injectable() export class GqlAuthGuard extends AuthGuard('jwt') { getRequest(context: ExecutionContext) { const ctx = GqlExecutionContext.create(context); return ctx.getContext().req; } }

Підписки (Реальний час)

typescript
@Resolver(() => Message) export class MessagesResolver { @Subscription(() => Message, { filter: (payload, variables) => payload.messageAdded.roomId === variables.roomId, }) messageAdded(@Args('roomId') roomId: string) { return pubSub.asyncIterator('messageAdded'); } @Mutation(() => Message) async sendMessage(@Args('input') input: SendMessageInput) { const message = await this.messagesService.create(input); pubSub.publish('messageAdded', { messageAdded: message }); return message; } }

DataLoader (Проблема N+1)

typescript
import DataLoader from 'dataloader'; @Injectable({ scope: Scope.REQUEST }) export class PostsLoader { constructor(private postsService: PostsService) {} readonly batchPosts = new DataLoader<string, Post[]>( async (userIds: string[]) => { const posts = await this.postsService.findByUserIds([...userIds]); return userIds.map((id) => posts.filter((p) => p.userId === id)); }, ); } // У розв'язувачі @ResolveField(() => [Post]) posts(@Parent() user: User) { return this.postsLoader.batchPosts.load(user.id); }

GraphQL проти REST

ОсобливістьRESTGraphQL
ОтриманняБагато кінцевих точокОдна кінцева точка
ПеревантаженняПоширенеКлієнт вказує поля
НедовантаженняБагато запитівОдин запит
ВерсіїНа основі URL (v1, v2)Еволюція схеми
КешуванняHTTP кешуванняСкладніше
Крива навчанняНижчаВища

Порада: Використовуйте GraphQL, коли вашому фронтенду потрібне гнучке отримання даних або коли у вас є кілька клієнтів (веб, мобільні) з різними вимогами до даних. Використовуйте REST для простіших API або коли важливе HTTP кешування.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань