從頭開始用 Typescript 打造一個 GraphQL server

李至青
Visually Lab
Published in
9 min readDec 25, 2019
Photo by Bárbara Sampaio on Unsplash

GraphQL 是什麼?

GraphQL 是一種設計在 API 中使用的資料查詢語法,其特色是能夠透過宣告式(Declarative)的語法,取得恰好所需的資料,並且同時提供了強型別的驗證。下圖上方為 GraphQL 查詢語法,下方為取得的資料。

圖片來源:https://graphql.org

該從哪裡開始認識 GraphQL?

要使用 GraphQL 之前,我們可能會遇到這些常見的問題:

  • GraphQL 如何提供資料的型別驗證?
  • GraphQL 如何與 Database 和 ORM 搭配使用?
  • 如何實作 GraphQL API ?

在下文中將會回答這些問題,說明如何使用 Typescript 描述 GraphQL schema 並與 ORM 搭配存取資料,並實作 API。分為以下步驟:

  • 初始化專案
  • 以 koa 設置 http 伺服器
  • 使用 class 定義你的 Data
  • 使用 class 定義 Resolver
  • 串接 Database 與 GraphQL server
  • 查詢資料

本篇中使用的工具與對應的問題

  • 使用 koa 作為 web server 處理外來的請求與路由
  • 使用 apollo-server 串接 koa 與 graphQL
  • 使用 typeORM 操作 database
  • 使用 typeGraphQL 產生 graphql schema 並創建 Resolver

初始化專案

首先,我們必須要先初始化專案

我預先設置好了 Typescript 的參數與安裝 NPM 套件,可以直接 clone 這個 Repository

$ git clone https://github.com/visuallylab/typescript-graphql-server-tutorial.git
  • 切換 Branch 到 1.starter

此外,這篇文章最後完成的程式碼可以在 Branch 2.add-user 看到

$ git checkout 1.starter
  • 安裝 node modules
$ yarn

這樣我們就設置好環境,可以準備開始寫 Typescript 了 🎉🎉🎉

以 Koa 設置 Http 伺服器

我們需要一個 Http 伺服器來接收外部的要求,在這裡使用 Koa 作為伺服器的 Framework

  • 創建資料夾 src ,然後創建第一個 ts 檔案 app.ts ,並放上以下內容
  • 啟動伺服器
$ yarn start

這就是一個基本的 Http 伺服器了!然後我們可以再回頭看看程式碼,在第 7 ~ 9 行的部分定義了在 /healthy 的路徑時要回傳 Visuallylab is awsome!

使用 class 定義你的 Data

接下來,我們要開始定義 Data 了,在這裡我們會使用 Typescript 的 class 描述資料,搭配 TypeGraphQL 與 TypeORM 這兩個套件,分別產出成 GraphQL schemaDatabase schema

  • 新增一個檔案 User.ts 放在 src/entities

在這裡我們定義了 User 的資料有三個屬性,並且型別都是 string

  • 然後我們要在 class 上標註產出 database schema 所需的資訊,先引入 TypeORM 所提供的 Decorator
  1. class 上方標註 @Entity 表示這個 Class 將會描述一個 table
  2. id 上方標註 @PrimaryGeneratedColumn(‘uuid’) 表示這個欄位由資料庫產生,並且為 Primary Key
  3. 然後在 name 以及 email 上標注 @Column,表示他們皆是 table 中的 Column,並且型別會是在下方標註的 string
  • 接著標註產出 GraphQL schema 所需的資訊,先引入 TypeGraphQL 所提供的 Decorator
  1. class 上方標註 @ObjectType 表示這個 Class 將會描述一個 Object
  2. id 上方標註 @Field(() => ID) 表示這個欄位將會對應到 GraphQL 中的 ID 型別
  3. 然後在 name 以及 email 上標注 @Field ,表示這個欄位將會是一個 GraphQL 的 Object property,這邊不需要指定型別,因為 string 將會自動對應到 GraphQL 中的 String type

使用 class 定義 Resolver

描述完資料後,我們要開始定義 Resolver,Schema 描述資料的模樣,Resolver 則描述我們可以如何取用這些資料。

  • 新增一個檔案 resolver.ts 放在 src/resolvers/user/

在這個檔案裡,我們同樣使用 class 定義了 User 的 Resolver,並提供了三個 API,

  1. query user
  2. query users
  3. mutation createUser

在程式碼中透過 Decorator 指定了 Resolver 的 API 接口,是 Query 或是 Mutation,以及回傳資料的格式。

另外,可以看到在 UserResolver 的 constructor 中的參數:

@InjectRepository(User) private readonly userRepository: Repository<User>

這一行是使用 typeDI 以 dependency injection 的方式讓 Resolver 可以存取 Database,但我們還沒有設置 Database 完成,因此這部分的程式碼要到下一段的步驟完成之後才能運作

串接 Database 與 GraphQL server

我們已經設置好 Data 的 schema 與 Resolver,最後,我們要把這些設置串接上 server。

  • 串接 Database

createConnections 中放入 database 的連線參數,另外要注意的是:

entities: [  
path.resolve(__dirname, ‘entities/*.ts’),
path.resolve(__dirname, ‘entities/*.js’),
]

Entities 這部分的路徑描述,必須要對應到 entities 的檔案路徑,typeORM 才會找到我們先前所定義好的 class 檔案

  • 串接 GraphQL

透過 typeGraphql 引入 buildSchema ,然後產生 apollo server。另外設置 typeGraphql 時,必須要記得引入 import ‘reflect-metadata’; 才能正常運作。

查詢資料

最後,我們可以執行伺服器來看看成果!

$ yarn start

打開瀏覽器輸入 http://localhost:8000/graphql,會看到以下這個畫面,這是 GraphQL playground,可以在左邊輸入 query,回傳的資料會直接顯示在右邊

可以在左邊輸入以下兩個語法看看成果

query {
users {
id
}
}
mutation {
createUser(user:{
name:"graphql is awsome",
email:"gql@gql.com"
}) {
id
name
}
}

謝謝你看到了最後:),這篇文章完成的程式碼可以在這裏瀏覽

回顧使用的工具與對應的問題

  • 使用 koa 作為 web server 處理外來的請求與路由
  • 使用 apollo-server 串接 koa 與 graphQL
  • 使用 typeORM 操作 database
  • 使用 typeGraphQL 產生 graphql schema 並創建 Resolver

延伸閱讀

  1. Backend-boilerplate:在這篇文章的程式碼為了容易解說與理解做了一些簡化,如果要作為實際的專案使用,可以參考這一個 Repo

2. TypeGraphQL 官網:在這裡可以看到 TypeGraphQL 更詳細的用法說明

3. GraphQL 官網:如果對於 Graphql type 不太了解,推薦先看官網的文件

4. TypeORM 官網:下方的 Getting start 有針對於更複雜的資料與 relation 的 ORM 使用做說明

--

--