Apollo + GraphQL — NestJS da ishlash

~25 daq · NestJS · Ilg'or mavzular

Muammodan boshlaylik

Oldingi darsda GraphQL nima ekanini bildik. Endi NestJS da qanday yozilishini ko'ramiz.

NestJS da code-first yondashuvi ishlatiladi: TypeScript yozasiz, GraphQL schema avtomatik yaratiladi. Avval sxema yozib, keyin resolver emas — aksincha.


O'rnatish

npm install @nestjs/graphql @nestjs/apollo @apollo/server graphql

Fayl tuzilmasi

src/
  users/
    dto/
      create-user.input.ts  ← mutation uchun kiritma
    user.model.ts            ← GraphQL tipi (@ObjectType)
    users.resolver.ts        ← so'rovlarni bajaruvchi
    users.service.ts         ← biznes logika
    users.module.ts
  app.module.ts              ← GraphQLModule shu yerda sozlanadi

AppModule ga ulash

// app.module.ts
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { join } from 'path';

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: join(process.cwd(), 'src/schema.gql'), // ← schema avtomatik yaratiladi
      playground: true, // ← brauzerda sinab ko'rish uchun
    }),
    UsersModule,
  ],
})
export class AppModule {}

ObjectType — GraphQL tipi

TypeScript klassidan GraphQL tipi yaratamiz:

// users/user.model.ts
import { ObjectType, Field, Int } from '@nestjs/graphql';

@ObjectType() // ← bu klass GraphQL tipiga aylanadi
export class User {
  @Field(() => Int) // ← Int tip
  id: number;

  @Field() // ← String tip (avtomatik)
  name: string;

  @Field()
  email: string;
}

NestJS bu klassdan schema avtomatik yaratadi:

type User {
  id: Int!
  name: String!
  email: String!
}

Resolver — so'rovlarni bajarish

Controller ga o'xshaydi, lekin HTTP o'rniga GraphQL so'rovlarini bajaradi:

// users/users.resolver.ts
import { Resolver, Query, Mutation, Args, Int } from '@nestjs/graphql';
import { User } from './user.model';
import { UsersService } from './users.service';
import { CreateUserInput } from './dto/create-user.input';

@Resolver(() => User)
export class UsersResolver {
  constructor(private usersService: UsersService) {}

  // query { users { id name } }
  @Query(() => [User])
  users() {
    return this.usersService.findAll();
  }

  // query { user(id: 1) { name } }
  @Query(() => User, { nullable: true })
  user(@Args('id', { type: () => Int }) id: number) {
    return this.usersService.findOne(id);
  }

  // mutation { createUser(input: {...}) { id } }
  @Mutation(() => User)
  createUser(@Args('input') input: CreateUserInput) {
    return this.usersService.create(input);
  }
}

InputType — mutation uchun

Ko'p argument o'rniga bitta ob'ekt:

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

@InputType()
export class CreateUserInput {
  @Field()
  name: string;

  @Field()
  email: string;
}

Frontend dan yuborish:

mutation {
  createUser(input: { name: "Ali", email: "ali@test.com" }) {
    id
    name
  }
}

Module

// users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersResolver } from './users.resolver';
import { UsersService } from './users.service';

@Module({
  providers: [UsersResolver, UsersService],
})
export class UsersModule {}

Playground da sinash

http://localhost:3000/graphql ga kiring:

# Barcha userlar
query {
  users {
    id
    name
    email
  }
}
# Bitta user
query {
  user(id: 1) {
    name
    email
  }
}
# Yangi user yaratish
mutation {
  createUser(input: { name: "Vali", email: "vali@test.com" }) {
    id
    name
  }
}

Tez-tez uchraydigan xatolar

1. Schema xatosi

Cannot determine GraphQL output type for "users"

Sababi: @Field() dekoratori yo'q yoki @ObjectType() unutilgan. Yechim: Barcha maydonlarga @Field() qo'ying, klassga @ObjectType() qo'ying.


2. Null xato

Cannot return null for non-nullable field User.name

Sababi: DB dan null keldi, lekin schema da String! (null bo'lmaydi deb belgilangan). Yechim: @Field({ nullable: true }) yoki DB dan ma'lumot to'g'ri kelishini tekshiring.


3. Playground ko'rinmayapti Sababi: Production muhitda playground avtomatik o'chadi. Yechim: GraphQLModule.forRoot({ playground: true }) — faqat development da.


Xulosa

  • @ObjectType() — GraphQL tipi (REST da model)
  • @InputType() — mutation uchun kiritma
  • @Query() — ma'lumot olish (REST da GET)
  • @Mutation() — o'zgartirish (REST da POST/PUT)
  • autoSchemaFile — TypeScript dan schema avtomatik yaratiladi
  • Playground — http://localhost:3000/graphql da sinab ko'rish

Keyingi dars: 44-dars: Event Emitter