Episode ini membahas integrasi GraphQL di NestJS: dasar GraphQL dengan @nestjs/graphql, pendekatan schema-first dan code-first, pembuatan resolver, input types, dan subscriptions, serta optimasi performa GraphQL dengan batching dan caching.

REST API kadang memaksa klien melakukan banyak request untuk satu tampilan. GraphQL memberi solusi: satu endpoint, dan klien menentukan persis data apa yang dibutuhkan. Episode 15 membahas dasar GraphQL di NestJS: pendekatan schema, resolver, input types, subscriptions, dan optimasi performa.
npm install @nestjs/graphql @nestjs/apollo graphql apollo-server-expressimport { Module } from "@nestjs/common";
import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
import { GraphQLModule } from "@nestjs/graphql";
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: true,
}),
],
})
export class AppModule {}Dengan autoSchemaFile: true, NestJS membuat schema secara otomatis dari kode kalian — inilah pendekatan code-first.
Pendekatan code-first mendefinisikan schema lewat dekorator TypeScript. Keuntungannya: schema dan kode selalu sinkron, dan ada type safety.
import { Field, ID, ObjectType } from "@nestjs/graphql";
@ObjectType()
export class User {
@Field(() => ID)
id: number;
@Field()
name: string;
@Field()
email: string;
}Dekorator @ObjectType dan @Field menghasilkan schema GraphQL secara otomatis.
Pendekatan schema-first menulis schema di file .graphql terlebih dahulu, lalu menghasilkan TypeScript. Cocok untuk tim yang ingin schema disepakati lebih dulu, misalnya untuk kontrak antar tim frontend dan backend.
Resolver adalah method yang menangani query dan mutation GraphQL:
import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
import { User } from "./user.model";
import { CreateUserInput } from "./create-user.input";
@Resolver(() => User)
export class UserResolver {
@Query(() => [User])
users(): User[] {
return [
{ id: 1, name: "Arman", email: "arman@example.com" },
];
}
@Mutation(() => User)
createUser(@Args("input") input: CreateUserInput): User {
return { id: 2, name: input.name, email: input.email };
}
}@Query menangani pembacaan, @Mutation menangani perubahan data.
Untuk input yang terstruktur, gunakan @InputType:
import { Field, InputType } from "@nestjs/graphql";
import { IsEmail, IsString, MinLength } from "class-validator";
@InputType()
export class CreateUserInput {
@Field()
@IsString()
@MinLength(3)
name: string;
@Field()
@IsEmail()
email: string;
}Input types juga bisa divalidasi dengan class-validator, sama seperti DTO di REST.
Subscriptions memungkinkan klien menerima update real-time:
import { Subscription } from "@nestjs/graphql";
import { PubSub } from "graphql-subscriptions";
@Resolver(() => User)
export class UserResolver {
constructor(private readonly pubSub: PubSub) {}
@Subscription(() => User)
userCreated(): AsyncIterator<User> {
return this.pubSub.asyncIterator("userCreated");
}
}Publisher memanggil pubSub.publish("userCreated", { userCreated: user }) saat user baru dibuat, dan klien yang subscribe menerima notifikasi secara langsung.
Masalah umum GraphQL adalah N+1 query — misalnya memuat author untuk setiap post. Solusinya DataLoader yang melakukan batching dan caching:
import * as DataLoader from "dataloader";
const authorLoader = new DataLoader(async (ids: readonly number[]) => {
const authors = await findAuthorsByIds([...ids]);
return ids.map((id) => authors.find((a) => a.id === id));
});Dengan batching, banyak request kecil digabung menjadi satu query database. Resolver juga bisa di-cache dengan CacheInterceptor untuk mengurangi beban database — kombinasi batching dan caching menjaga GraphQL API tetap cepat meski kompleksitas query bertambah.
Episode 15 memperkenalkan GraphQL di NestJS: setup dasar, pendekatan schema-first dan code-first, resolver dan input types, subscriptions, serta optimasi dengan batching dan caching.
Inti yang harus dibawa pulang:
@Query, @Mutation, dan @Subscription adalah tiga jenis operasi.