霍爾筆記

全端網站設計範例:後端新增 Apollo server

約 754 字 --

本篇為「全端網站架構」中的後端範例及細節。需先建立專案(請參閱上一篇:全端網站設計範例:後端專案建立)。

由於此專案前後端用 GraphQL 作為 API 的形式,考慮到便利性,前後端都會使用 Apollo 所提供的框架。

主要參閱 Get started with Apollo Server 這篇官方教學文來實做。

安裝 Apollo Server

我們使用 Apollo Server 4

$ npm install @apollo/server graphql

定義 GraphQL schema

$ touch src/schemas.graphql

打開 src/schemas.graphql 並編輯其內容,建立最基本的範例

type Query {
  hello: String!
}

定義 Resolver

$ mkdir src/resolvers
$ touch src/resolvers/index.ts

打開 src/resolvers/index.ts 並編輯其內容,建立最基本的範例

export default {
  Query: {
    hello: (): string => 'world',
  },
};

建立 Apollo Server

編輯 src/index.ts

import * as fs from 'fs';
import * as path from 'path';
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import resolvers from './resolvers';

const server = new ApolloServer({
  typeDefs: fs.readFileSync(path.join(__dirname, 'schemas.graphql'), 'utf8'),
  resolvers,
});

(async () => {
  const { url } = await startStandaloneServer(server, { listen: { port: 5000 } });
  console.log(`Server is running at ${url}`);
})();

建立一個 Apollo Server 需要提供 GraphQL schema 的定義,由於 .graphql 無法被直接 import,我們用讀檔的方式把 schema 讀進來。另外再將 resolvers 傳入 Apollo Server,最後呼叫 listen() 啟動伺服器監聽即可。

最後瀏覽 http://localhost:5000 (根據環境變數 PORT 調整),在 Apollo Server v3 後的版本中,會導頁至他們的新版 Query Tool - Apollo Sandbox,就可以進行 Query 的開發操作了(原本 v2 中是用 GraphQL Playground 這個 tool)。

ESLint 可能問題

import resolvers from './resolvers' 時遇到 import/no-unresolved

error    Unable to resolve path to module './resolvers'  import/no-unresolved

參閱 StackOverflow - Using eslint with typescript - Unable to resolve path to module,在 .eslintrc.json 中加上以下程式碼即可解決問題

{
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"]
      }
    }
  }
}

import resolvers from './resolvers' 時遇到 import/extensions

error    Missing file extension "ts" for "./resolvers"  import/extensions

參閱 Typescript eslint - Missing file extension “ts” import/extensions,在 .eslintrc.json 中加上以下程式碼即可解決問題

"rules": {
   "import/extensions": [
      "error",
      "ignorePackages",
      {
        "js": "never",
        "jsx": "never",
        "ts": "never",
        "tsx": "never"
      }
   ]
}

加上 Logging 機制

記錄 Log 在專案中也是必不可少的機制,這裡我們使用 npmlog 來記錄。

$ npm install npmlog
$ npm install -D @types/npmlog

index.ts 中的 console.log 替換成 npmlog。

import log from 'npmlog';

server.listen({ port: process.env.PORT || 5000 }).then(({ url }) => {
  log.info('index', `Server is running at ${url}`);
});

加上時間

預設的 log 是沒有列出時間的,可以參考這個 issue npmlog - Add option to log timestamp 來加上時間。在 index.ts 中加上以下程式碼

Object.defineProperty(log, 'heading', { get: () => new Date().toUTCString() });
log.headingStyle = { bg: '', fg: 'white' };

印出的 log 就會像是:Wed, 25 Aug 2021 08:39:51 GMT info index Server is running at http://localhost:5000/

參考資料

  1. Get started with Apollo Server
  2. npmlog

CHANGELOG

日期敘述
2024-03-04更新使用的工具版本、建立專案細節
2021-08-20初版
全端網站設計範例 #fullstack