มาลองใช้ NestJS ทำ GraphQL Server กัน (ฉบับผู้เริ่มต้น)

notallowall

NotAllow

Posted on April 11, 2020

มาลองใช้ NestJS ทำ GraphQL Server กัน (ฉบับผู้เริ่มต้น)

ทุกวันนี้ผมใช้ express + apollo ทำ GraphQL Server แต่ปีนี้ในทีมก็มีมติว่าจะเปลี่ยนไปเขียน TypeScript ซึ่งจะตอบโจทย์ในเรื่องของ NewBie Mistakes ตอนแรกว่าจะเขียนไว้อ่านเอง แต่ก็อยากมาแชร์ให้ทุก ๆ คนมาลองดูกันครับ

มาทำความรู้จักกันครับว่า NestJS คืออะไร

NestJS อย่างที่หลาย ๆ คนทราบกันดีอยู่แล้วว่ามันคือ Framework ตัวนึงที่เขียนด้วย TypeScript และออกแบบมาโดยใช้แนวคิด OOP กับ Fuctional Programming เข้าด้วยกัน ซึ่ง NestJS ก็อาศัยการทำงานของ HTTP Server ที่เราสามารถเลือกใช้ได้ก็จะเป็น Express หรือ Fastify ในบทความนี้ผมขอใช้ Express แล้วกันนะครับ

มาเริ่มกันเลยดีกว่า

ติดตั้ง Nest CLI กันก่อน ด้วย Command ตามนี้

$ npm i -g @nestjs/cli
Enter fullscreen mode Exit fullscreen mode

เสร็จแล้วก็สร้างโปรเจค

$ nest new nestjs-graphql-starter
Enter fullscreen mode Exit fullscreen mode

แล้วมันจะขึ้นให้เลือก package manager ว่าจะใช้ npm หรือ yarn ในทีนี้ผมก็เลือก yarn นะครับ

Which package manager would you ❤️  to use? npm or yarn
Enter fullscreen mode Exit fullscreen mode

เท่านี้ก็จะได้ Nestjs project structer มาแล้วครับ ต่อมาเราจะมาเริ่มใช้ GrahpQL ร่วมกับ NestJS กัน

ก่อนอื่นก็มาติดตั้ง GraphQL กันด้วยคำสั่ง

$ yarn add @nestjs/graphql graphql-tools graphql // or npm i --save @nestjs/graphql graphql-tools graphql
Enter fullscreen mode Exit fullscreen mode

ต่อมาติดติ้ง Http server จะเลือกใช้ตัวไหนก็ได้ระหว่าง express กับ fastify

กรณีเลือกใช้ express ใช้คำสั่ง

$ yarn add apollo-server-express // or npm i --save apollo-server-express
Enter fullscreen mode Exit fullscreen mode

กรณีเลือกใช้ fastify ใช้คำสั่ง

$ yarn add apollo-server-fastify // or npm i --save apollo-server-fastify
Enter fullscreen mode Exit fullscreen mode

เข้า Folder ที่สร้างเมื่อกี้ด้วย Editor Tool แล้วหาไฟล์ nest-cli.json ใส่ code ตามนี้

{
  "compilerOptions": {
    "plugins": ["@nestjs/graphql/plugin"]
  }
}
Enter fullscreen mode Exit fullscreen mode

ต่อมาแก้ไขไฟล์ ./src/app.module.ts เพื่อเรียกใช้งาน graphql ตาม code ด้านล่างนี้ได้เลยครับ

import { Module } from '@nestjs/common'
import { GraphQLModule } from '@nestjs/graphql'

@Module({
  imports: [
    GraphQLModule.forRoot({
      installSubscriptionHandlers: true,
      autoSchemaFile: 'schema.gql',
      debug: false,
      playground: true,
    }),
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

จาก code ด้านบน

installSubscriptionHandlers: true ไว้สำหรับเลือกเปิดใช้งาน Subscription หรือไม่
autoSchemaFile: 'schema.gql' ไว้ generate file typeDefs schema เพื่อนำไปไว้ Build เพื่อ Run Apollo Server
debug: false ไว้สำหรับจะเลือกใช้งาน debug หรือไม่
playground: true ไว้สำหรับเลือกเปิดใช้งาน playgroud client หรือไม่

ต่อมาพระเอกของเรากันดีกว่า Nest มี CLI ไว้สร้าง Module,Interface,Resolver,Service
มาสร้าง module กัน ด้วยคำสั่ง

$ nest g module {name} //or nest g mo {name}
Enter fullscreen mode Exit fullscreen mode

ตัวอย่างผมจะสร้าง module ชื่อ book ก็ใช้คำสั่ง

$ nest g mo book
Enter fullscreen mode Exit fullscreen mode
$ nest g resolver {name} //or nest g r {name}
Enter fullscreen mode Exit fullscreen mode

ตัวอย่างผมจะสร้าง Resolver ชื่อ book ก็ใช้คำสั่ง

$ nest g r book
Enter fullscreen mode Exit fullscreen mode

ทีนี้ NestJS ก็ได้ออก Decorator ของตัวเองเพื่อทำ DTO (Data Transfer Object) ไว้แล้ว โดยที่เมื่อก่อนยืมของ TypeGraphQL มาใช้ก่อน งั้นเรามาเริ่มสร้าง Model กัน
สร้างโดยการ Create Folder ให้อยู่ใน Directory Book ที่ ./src/book/models/book.model.ts

import { Field, ID, ObjectType } from '@nestjs/graphql'

@ObjectType()
export class Book {
  @Field(type => ID)
  id: string

  @Field(type => String, { nullable: true })
  name?: string

  @Field(type => String, { nullable: true })
  description?: string

  @Field(type => Number, { nullable: true })
  price?: number

  @Field(type => [String], { nullable: true })
  writer?: string[]
}
Enter fullscreen mode Exit fullscreen mode

ถ้าต้องการให้ Field มีค่าเป็น null ได้ ให้ใส่ options เพิ่มคือ { nullable: true } และใส่ ? หลังตัวแปรเพื่อละเว้นให้เป็น optional ได้

เสร็จแล้วสร้าง DTO ไว้หรับ Type Input กันเถอะเพื่อไปใช้เป็น Variable ตอนเรียกใช้งานกัน

create folder dto ให้อยู่ใน Directory Book ที่ ./src/book/dto
แล้ว create file book.input.ts อยู่ใน folder dto
เมื่อสร้างแล้วเขียน code ตามนี้เลยครับ

import { Field, InputType } from '@nestjs/graphql'

@InputType()
export class InputBook {
  @Field(type => String)
  name: string

  @Field(type => Number, { nullable: true })
  price?: number

  @Field(type => String, { nullable: true })
  description?: string

  @Field(type => [String])
  writer: string[]
}
Enter fullscreen mode Exit fullscreen mode

ถ้าต้องการให้ Field ไหนเป็น Array ให้ใส่ [] คอบ Type นั้นได้เลยครับ

มาจัดการกับ Resolver กัน ในบทความที่ผมเขียนนี้จะยกการทำ Mutation กับ Query ไว้เท่านี้ก่อนนะครับเพื่อไม่ให้บทความมีความยาวมากเกินไป

กลับมาที่ File : book.resolver.ts แล้วเขียน Code สร้าง Mutation กับ Query กันตามนี้เลยครับ ขออนุญตาติฟิกค่า return เลยนะครับ

import { Resolver, Query, Mutation, Args } from '@nestjs/graphql'
import { Book } from './models/book.model'
import { InputBook } from './dto/book.input'

@Resolver('Book')
export class BookResolver {
  @Query(returns => Book)
  getBook(): Book {
    const result: Book = {
      id: '1',
      name: 'BeforeSecond',
      price: 199,
    }
    return result
  }

  @Mutation(returns => Book)
  createBook(@Args('input') input: InputBook): Book {
    const result: Book = {
      id: '2',
      ...input,
    }
    return result
  }
}
Enter fullscreen mode Exit fullscreen mode

เสร็จแล้วลองรันกันครับ

$ yarn start:dev
Enter fullscreen mode Exit fullscreen mode

เข้า Web Browser เปิด URL: http://localhost:3000/graphql

ทดสอบ Query กัน

ใส่ Code Query ดังนี้

query {
  getBook{
    id
    name
    price
    description
    writer
  }
}
Enter fullscreen mode Exit fullscreen mode

ปรากฏว่าได้ผลลัพทธ์

{
  "data": {
    "getFirst": {
      "id": "1",
      "name": "first"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

ทดสอบ Mutation กัน

mutation {
  createBook(input:{
    name:"test",
    description:"ทดสอบ",
    price:299,
    writer:["First","BeforeSecond"]
  }){
    id
    name
    price
    description
    writer
  }
}
Enter fullscreen mode Exit fullscreen mode

ผลลัพท์

{
  "data": {
    "createBook": {
      "id": "2",
      "name": "test",
      "price": 299,
      "description": "ทดสอบ",
      "writer": [
        "First",
        "BeforeSecond"
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Very Good 👍👍👍👍👍

สรุปได้ว่า NestJS ก็เป็นอีกทางเลือกนึงที่สามารถทำ GraphQL Server ได้ด้วยการเขียน TypeScript ที่ผมคิดว่าตอบโจทย์ได้ดีเลยทีเดียวครับ โดยปกติถ้าเขียน Express+Apollo เราจะต้องมานั่งทำ typeDefs เอง หรือบ้างก็ไปใช้ CLI codegen:generate แต่ NestJS ทำให้เราสะดวกมากขึ้นไปเยอะเลย ยิ่งถ้าใช้ TypeORM หรือ Sequelize นี่ยิ่งสบายเลยกับการเขียน GraphQL มาก ๆ เลยครับ

สุดท้ายนี้ ถ้าผิดพลาดต้องขอภัยด้วยนะครับ ขอบคุณที่อ่านมาจนจบครับผม 😀
สามารถศึกษาเพิ่มเติมได้ที่
Referense: https://docs.nestjs.com/graphql/quick-start

💖 💪 🙅 🚩
notallowall
NotAllow

Posted on April 11, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related