NextJS và Graphql với Apollo Client
minhthuong031103
Ta đã có sẵn NestJS Graphql, Tạo thêm resource Product mới
import { ObjectType, Field, Int } from '@nestjs/graphql';
@ObjectType()
export class Product {
@Field(() => Int)
id: number;
@Field()
description: string;
@Field()
price: number;
@Field(() => Int, { defaultValue: 0 })
quantity?: number;
@Field()
name: string;
@Field()
image: string;
@Field()
createdAt: Date;
@Field()
updatedAt: Date;
}
import { Injectable } from '@nestjs/common';
import { CreateProductInput } from './dto/create-product.input';
import { UpdateProductInput } from './dto/update-product.input';
import { PrismaService } from 'src/prisma.service';
@Injectable()
export class ProductService {
constructor(private prisma: PrismaService) {}
findAll() {
return this.prisma.product.findMany({ where: {} });
}
findOne(id: number) {
return this.prisma.product.findUnique({ where: { id: id } });
}
}
Resolver sẽ như này
import { Resolver, Query, Mutation, Args, Int } from '@nestjs/graphql';
import { ProductService } from './product.service';
import { Product } from './entities/product.entity';
import { CreateProductInput } from './dto/create-product.input';
import { UpdateProductInput } from './dto/update-product.input';
import { Public } from 'src/auth/decorations/public.decorator';
@Resolver(() => Product)
export class ProductResolver {
constructor(private readonly productService: ProductService) {}
@Public()
@Query(() => [Product], { name: 'products' })
products() {
return this.productService.findAll();
}
@Public()
@Query(() => Product, { name: 'product' })
findOne(@Args('id', { type: () => Int }) id: number) {
return this.productService.findOne(id);
}
}
giờ tạo next app
npx create-next-app@latest ./
npm run dev
npm i @apollo/client graphql @apollo/experimental-nextjs-app-support
npm i -D @graphql-codegen/cli
npm i @graphql-codegen/typescript @graphql-codegen/typescript-operations
Mục đích của codegen đso là tạo ra type dùng được trong type script dựa trên các objecttype và inputtype
của thằng Graphql bên server dưới dạng scalar
ta tạo file codegen.yml
schema: http://localhost:4000/graphql //host của graphql
documents: 'graphql/**/*.ts'
generates:
./graphql/types.ts: //nơi file types sẽ được tạo ra, nhớ tạo folder graphql
plugins:
- typescript
- typescript-operations
giờ chỉnh trong package.json script
"codegen": "graphql-code-generator --config ./codegen.yml --watch"
tạo file query
import { gql } from 'graphql-tag';
export const getProducts = gql`
query GetAllProducts {
products {
id
name
price
description
image
quantity
createdAt
updatedAt
}
}
`;
Để dùng được query trong server component thì phải tạo 1 file client.ts, xuất ra hàm
getClient()
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { registerApolloClient } from '@apollo/experimental-nextjs-app-support/rsc';
export const { getClient } = registerApolloClient(() => {
return new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
// https://studio.apollographql.com/public/spacex-l4uc6p/
uri: 'http://localhost:4000/graphql',
// you can disable result caching here if you want to
// (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
// fetchOptions: { cache: "no-store" },
}),
});
});
=> giờ fetch data trong server component
const client = getClient(); =>import import { getClient } from '@/lib/client';
const { data} = await client.query({ query: getProducts });
//import { getProducts } from '@/graphql/getProducts.query';
Nếu muốn dùng variable
const { data } = await client.query({
query: getProductById,
variables: { id: Number(params.id) },
});
Ok vậy là xong
Nếu dùng static prop, path thì tham khảo
export async function getStaticProps({ params }: { params: { id: string } }) {
const { data } = await client.query<
GetProductByIdQuery,
GetProductByIdQueryVariables
>({
query: getProductById,
variables: { id: Number(params.id) },
})
return {
props: {
product: data.product,
},
}
}
export async function getStaticPaths() {
const { data } = await client.query<GetAllProductsQuery>({
query: getAllProducts,
})
const paths = data.products.map((product) => ({
params: { id: product.id.toString() },
}))
return {
paths,
fallback: false,
}
}