Node 只要安裝 Redis Client,就能存取 Redis,但其提供為 Callback-based API,要轉成 Promised-based API 後才方便在 Resolver 使用。
Version
macOS Catalina 10.15.1
Docker Desktop 2.1.0.5 (40693)
WebStorm 2019.3
Node 13.2.0
Apollo GraphQL 2.9.6
Redis 5.0.6
Redis Client 2.8.0
Docker Compose
redis/docker-compose.yml
version: "3"
services:
redis:
image: redis:latest
container_name: MyRedis
volumes:
- ${REDIS_HOST_DIR}:/data
ports:
- ${REDIS_PORT}:6379
restart: always
第 5 行
image: redis:latest
使用 Redis 最新版 image。
第 6 行
container_name: MyRedis
使用 container_name
定義 container 名稱為 MyRedis
。
第 7 行
volumes:
- ${REDIS_HOST_DIR}:/data
設定 Redis database 實際儲存在 macOS 路徑,避免 container 結束後 database 也跟著刪除。
第 9 行
ports:
- ${REDIS_PORT}:6379
設定 Redis 對外使用 host os 的 port。
.env
REDIS_HOST_DIR=.redis
REDIS_PORT=6379
建立 .env
設定 docker-compose.yml
所需環境變數。
REDIS_HOST_DIR
:設定 Redis database 要存到 Host OS 位置REDIS_PORT
:設定 Redis 對應到 Host OS 的 port
Install Package
$ yarn add apollo-server graphql
$ yarn add redis
- Apollo GraphQL 安裝
apollo-server
與grapql
- Redis Client 安裝
redis
Apollo GraphQL
src/index.js
import { ApolloServer, gql } from 'apollo-server'
import { createClient } from 'redis'
import { promisify } from 'util'
let redis = createClient({
host: 'localhost',
port: 6379
})
let getAsync = promisify(redis.get).bind(redis)
let typeDefs = gql`
type Query {
hello: String
}
`
let hello = async () => await getAsync('hello')
let resolvers = {
Query: {
hello
}
}
new ApolloServer({ typeDefs, resolvers })
.listen()
.then(({ url }) => `GraphQL Server ready at ${ url }`)
.then(console.log)
第 1 行
import { ApolloServer, gql } from 'apollo-server'
從 apollo-server
引入 AplloServer
與 gql
。
第 2 行
import { createClient } from 'redis'
從 redis
引入 createClient
建立 Redis client object。
第 3 行
import { promisify } from 'util'
從 util
引入 promisify
將 Redis client 的 api 從 callback-based 轉成 promised-based。
第 5 行
let redis = createClient({
host: 'localhost',
port: 6379
})
使用 createClient()
建立 Redis client,傳入 option object 指定 host
與 port
。
第 10 行
let getAsync = promisify(redis.get).bind(redis)
使用 promisify()
將 redis.get()
由 callback-based 轉成 promised-based,但因 promisify()
回傳為 standalon function,要使用 bind()
將 client
的 this
重新綁定回去。
12 行
let typeDefs = gql`
type Query {
hello: String
}
`
在 GraphQL schema 宣告 hello
query。
19 行
let resolvers = {
Query: {
hello
}
}
在 resolvers
宣告 hello
query。
17 行
let hello = async () => await getAsync('hello')
由於 getAysnc()
回傳 promise,因此 hello()
要宣告成 async
function 搭配 await
。
25 行
new ApolloServer({ typeDefs, resolvers })
.listen()
.then(({ url }) => `GraphQL Server ready at ${ url }`)
.then(console.log)
建立 Apollo GraphQL 並使用 listen()
啟動之。
GraphQL Playground
Conclusion
- Apollo client 原本提供的
get()
為 callback-based API,搭配 GraphQL 的 resolver 較不方便,透過promisify()
轉成 promised-based API 後,在 resolver 只要使用async await
就可輕鬆使用
Sample Code
完整範例可在我的 GitHub 上找到