Home About Projects Blogs 
MTH

2025 © All Rights Reserved.
Built with ♡ by MinhThuong
Say Hello

NextJS và Graphql với Apollo Client

anh

minhthuong031103

  • https://github.com/minhthuong031103
  • Jun 18, 2023
  • 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,
      }
    }