從頭開始用 Typescript 打造一個 GraphQL server
GraphQL 是什麼?
GraphQL 是一種設計在 API 中使用的資料查詢語法,其特色是能夠透過宣告式(Declarative)的語法,取得恰好所需的資料,並且同時提供了強型別的驗證。下圖上方為 GraphQL 查詢語法,下方為取得的資料。
該從哪裡開始認識 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://localhost:8000/healthy 打開會看到以下畫面
這就是一個基本的 Http 伺服器了!然後我們可以再回頭看看程式碼,在第 7 ~ 9 行的部分定義了在 /healthy
的路徑時要回傳 Visuallylab is awsome!
使用 class 定義你的 Data
接下來,我們要開始定義 Data 了,在這裡我們會使用 Typescript 的 class 描述資料,搭配 TypeGraphQL 與 TypeORM 這兩個套件,分別產出成 GraphQL schema 與 Database schema
- 新增一個檔案 User.ts 放在 src/entities
在這裡我們定義了 User 的資料有三個屬性,並且型別都是 string
- 然後我們要在 class 上標註產出 database schema 所需的資訊,先引入 TypeORM 所提供的 Decorator
- 在
class
上方標註@Entity
表示這個 Class 將會描述一個 table - 在
id
上方標註@PrimaryGeneratedColumn(‘uuid’)
表示這個欄位由資料庫產生,並且為 Primary Key - 然後在
name
以及email
上標注@Column
,表示他們皆是 table 中的Column
,並且型別會是在下方標註的string
- 接著標註產出 GraphQL schema 所需的資訊,先引入 TypeGraphQL 所提供的 Decorator
- 在
class
上方標註@ObjectType
表示這個 Class 將會描述一個 Object - 在
id
上方標註@Field(() => ID)
表示這個欄位將會對應到 GraphQL 中的 ID 型別 - 然後在
name
以及email
上標注@Field
,表示這個欄位將會是一個 GraphQL 的 Object property,這邊不需要指定型別,因為 string 將會自動對應到 GraphQL 中的 String type
使用 class 定義 Resolver
描述完資料後,我們要開始定義 Resolver,Schema 描述資料的模樣,Resolver 則描述我們可以如何取用這些資料。
- 新增一個檔案 resolver.ts 放在 src/resolvers/user/
在這個檔案裡,我們同樣使用 class 定義了 User 的 Resolver,並提供了三個 API,
- query user
- query users
- 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
延伸閱讀
- Backend-boilerplate:在這篇文章的程式碼為了容易解說與理解做了一些簡化,如果要作為實際的專案使用,可以參考這一個 Repo
2. TypeGraphQL 官網:在這裡可以看到 TypeGraphQL 更詳細的用法說明
3. GraphQL 官網:如果對於 Graphql type 不太了解,推薦先看官網的文件
4. TypeORM 官網:下方的 Getting start 有針對於更複雜的資料與 relation 的 ORM 使用做說明