มาลองเล่น Deno GraphQL พร้อมกับทำ Deno Hot Reload กันเถอะ
Tags: deno, graphql, typescript, denon
Published: 2020-05-29 16:34:03

มาวันนี้หลาย ๆ คนก็น่าจะรู้จัก Deno มาสักพักแล้ว Deno เป็น Runtime ตัวใหม่ของ
Javascript ที่จะมาแทน Node ในอนาคตสำหรับใครยังไม่ได้ติดตั้ง Deno ไปติดตั้งกันเลยดีกว่า

#Install Deno กัน
สำหรับ MacOS ใช้ Homebrew ไปเลย แต่ถ้าใช้ OS อื่น ๆ สามารถดูการติดตั้งได้ที่นี่เลย https://deno.land/#installation

```shell
brew install deno
```

หลังจากที่เราได้ `Deno` มาแล้วก็มาเข้าเรื่องกันผมจะขอทำ Hot Reload และมาพูดต่อถึงการเขียน GraphQL นะครับ

##มาเริ่มติดตั้ง Hot Reload ดีกว่า
สำหรับสาย NodeJS คงไม่พ้น Nodemon พอมา Deno ก็มีให้ใช้เหมือนกันนั่นคือ Denon
ขั้นตอนการติดตั้งก็ง่าย ๆ 
สิ่งที่ต้องมีคือ Deno Version 1.0.1 ขึ้นไป ก่อนจะติดตั้งมาอัพเกรด Deno เป็น Version ล่าสุดกันก่อนโดยใช้คำสั่ง `deno upgrade` อัพเกรดเสร็จแล้ว ก็ติดตั้ง Denon กันได้เลย
```shell
deno install --allow-read --allow-run --allow-write -f --unstable https://deno.land/x/denon/denon.ts
```

หลังจากติดตั้งมาแล้วให้ `export PATH="$HOME/.deno/bin:$PATH"` เพื่อใช้ในการ Execute Deno ที่ได้ติดตั้งมา
เพียงเท่านี้คุณก็จะมี Denon ไว้ทำ Hot Reload แล้วต่อมา เริ่มสร้าง Project Deno GraphQL กัน

##GraphQL
บทความนี้ขออนุญาติไม่พูดถึง GraphQL นะครับ เพราะคิดว่าน่าจะพอทราบ ๆ กันบ้างแล้วเนอะ
สิ่งที่ผมใช้คือ OAK ซึ่งเป็น middleware framework ไว้ทำ http server มาเริ่มกันเลยยย
```
├── denon.json
├── src
│   ├── index.ts
│   └── resolvers
│       ├── index.ts
│       └── user.ts
└── tsconfig.json
```
ผมจะวางโครงสร้างไว้คร่าว ๆ ตามนี้ครับ
มาสร้าง Denon ให้กับ project นี้กันก่อนโดยใช้คำสั่ง
```shell
denon init
```
เสร็จแล้วจะมีไฟล์ `denon.json` ให้เราทำการแก้ไขดังนี้
```json
{
  "$schema": "https://deno.land/x/denon/schema.json",
  "scripts": {
    "start": "deno run --allow-net ./src/index.ts"
  }
}

```

เสร็จแล้วก็ไขไฟล์ `./src/index.ts` ใส่ code ตามข้างล่างนี้ได้เลยครับ
```typescript
import { Application } from 'https://deno.land/x/oak/mod.ts'
import { GraphQLService } from './resolvers/index.ts'

const app = new Application()

app.use(async (ctx, next) => {
  await next()
  const rt = ctx.response.headers.get('X-Response-Time')
  console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`)
})

app.use(async (ctx, next) => {
  const start = Date.now()
  await next()
  const ms = Date.now() - start
  ctx.response.headers.set('X-Response-Time', `${ms}ms`)
})

await app.use(
  await GraphQLService.routes(),
  await GraphQLService.allowedMethods()
)

console.log('Server start at http://localhost:8080')
console.log('Playgroud at http://localhost:8080/graphql')
await app.listen({ port: 8080 })

```

เสร็จแล้วมาเขียน resolvers กัน
ให้แก้ไข code ไฟล์ `./src/resolvers/user.ts` ส่วนตัวผมชอบ TypeDefs ไว้ที่เดียวกับ Resolvers นะครับ เพราะเวลาจะหา TypeDefs หรือจะแก้ไข Resolvers จะได้แก้ที่ไฟล์เดียวกันไปเลย
```typescript
import { gql } from 'https://deno.land/x/oak_graphql/mod.ts'

export const resolvers = {
  Query: {
    getUser: (parent: any, { id }: any, context: any, info: any) => {
      console.log('id', id, context)
      return {
        firstName: 'wooseok',
        lastName: 'lee',
      }
    },
  },
  Mutation: {
    setUser: (
      parent: any,
      { firstName, lastName }: any,
      context: any,
      info: any
    ) => {
      console.log('input:', firstName, lastName)
      return {
        done: true,
      }
    },
  },
}

export default gql`
  type User {
    firstName: String
    lastName: String
  }

  input UserInput {
    firstName: String
    lastName: String
  }

  type ResolveType {
    done: Boolean
  }

  type Query {
    getUser(id: String): User
  }

  type Mutation {
    setUser(input: UserInput!): ResolveType!
  }
`

```
เสร็จแล้วมา import ใช้ Resolvers และ TypeDefs จากไฟล์ `./src/resolvers/user.ts` ใน `./src/reolvers/index.ts` กันครับ ก็จะได้ตาม code ตัวอย่างด้านล่างนี้
```typescript
import { applyGraphQL } from 'https://deno.land/x/oak_graphql@0.1/mod.ts'
import user, { resolvers as UserResolvers } from './user.ts'

export const GraphQLService = await applyGraphQL({
  typeDefs: [await user],
  resolvers: [await UserResolvers],
})

```
เสร็จแล้วสั่ง `denon start` แล้วลองเล่น Playgroud ดูครับถ้าไม่ผิดพลาดอะไรน่าจะได้ตามรูปด้านล่างนี้ครับ
![Login](https://images2.imgbox.com/48/37/x3C8in7m_o.png)
เสร็จแล้วครับ ขอบคุณที่มาอ่านกันอย่างไรก็ตามขอให้บทความนี้พอจะมีประโยชน์กับผู้อ่านไม่มากก็น้อยนะครับ ผิดพลาดประการใด ขออภัยมา ณ ที่นี้ด้วยครับ 
ป.ล. ขอให้สนุกกับไดโนเสาร์นะครับ 😀