Apollo Serverをどこかにデプロイして試してみたい!
そう思って調べてみるとCloud Functions for Firebaseが対応している事が分かりました。
Firebaseは使い慣れている事もあったため、
Cloud Functions for FirebaseにApollo Serverをデプロイしてみる事にしました。
検証した環境
1 | firebase | 11.0.1 |
2 | express | 4.18.1 |
3 | apollo-server-express | 3.8.1 |
4 | graphql | 16.5.0 |
開発を行う前の準備
先にFirebaseのWebサイトからプロジェクトを作成しておきます
表示された通りに進めていきプロジェクトの作成が完了すればOKです!
Functionsを使うためのローカル環境の作成
Cloud Functions for Firebaseをローカルで試す方法はGoogleがしっかり用意してくれていて、
インストール方法も丁寧にまとめられています。
はじめに: 最初の関数の記述、テスト、デプロイ | Firebase Documentation
Cloud Functions for Firebaseをエミュレートしたものを firebase-functions と言うみたいですね
まずローカル環境を作成するためのコマンドをグローバルにインストールします。
$ npm install -g firebase-tools
↑を実行するとfirebase
というコマンドが使用出来るようになります。
$ firebase --version
11.0.1
firebase-toolsをインストールした最初はログインが必要になります。
$ firebase login
ローカルで実行するための環境を作成します
$ firebase init functions
いくつか質問されるため答えていきます。私は今回以下のように答えました。
- Use an existing project・・先ほど作ったプロジェクトを選択
- What language would you like to use to write Cloud Functions?・・TypeScript
- Do you want to use ESLint to catch probable bugs and enforce style?・・Y
- ESLintの導入
- Do you want to install dependencies with npm now?・・n
- npmを使ってライブラリをインストールするか?(私はyarnを使いたいのでここではNOを選択)
全て答え終わると必要なファイル一式が作成されます。
firebase functionsのライブラリをインストール
今回は最後の質問で「NO」選択していてライブラリが未インストールになっています。
そのためライブラリのインストールから行います。
firebase functionsの処理はfunctionsフォルダの中に書くので移動します。
$ cd functions/
package.jsonに記載されているnodeのバージョンと合わせるため
nodenvを使ってnodeのバージョンを固定します。
{
"engines": {
"node": "16"
},
・・・
}
package.jsonの記載が16なので記事を書いている時LTSの16.15.0
をインストール
$ nodenv local 16.15.0
nodeのバージョンを固定出来たらライブラリをインストールします
$ yarn install
npmの部分を書き換える
firebase init
した際に自動的にnpm-scriptsも作られています(便利)が、
内部でnpmを利用しているのでyarnに書き換えます。
具体的には serve
・shell
・start
の3つです
"scripts": {
"serve": "yarn run build && firebase emulators:start --only functions",
"shell": "yarn run build && firebase functions:shell",
"start": "yarn run shell",
・・・
}
ローカルで動くようにする
hello worldにあたるコードがコメントアウトする形で添付されています。
コメントアウトを外して動かせるようにします
import * as functions from "firebase-functions";
// Start writing Firebase Functions
// https://firebase.google.com/docs/functions/typescript
export const helloWorld = functions.https.onRequest((request, response) => {
functions.logger.info("Hello logs!", {structuredData: true});
response.send("Hello from Firebase!");
});
ここまで出来たら試しに実行してみます!
$ yarn run serve
・・・
✔ functions[us-central1-helloWorld]: http function initialized (http://localhost:5001/xxxxxx/us-central1/helloWorld).
・・・
コマンドを実行すると沢山の情報が出力されますが、
目を凝らすと ↑ のような1行が表示されているのでブラウザでアクセスします。
無事文字が表示されました!
GraphQLの実装
firebase functionsを動かす下地が出来たので、GraphQLを動かせるようにしていきます。
実装方法は複数あるようなのですが、
いざという時の対応がしやすく記事も多くある express
を使った実装 をしていきます。
まず必要なパッケージをインストールします。
注意点としては引き続きfunctionsフォルダで実行する必要がある、ということです。
$ yarn add express apollo-server-express graphql
apollo-server-express
はexpressとApollo Serverを統合するためのパッケージで、
Apollo Server公式に以下のように書かれています。
apollo-server-express is the Apollo Server package for Express, the most popular Node.js web framework. It enables you to attach a GraphQL server to an existing Express server.
[翻訳] apollo-server-expressは、Node.jsのWebフレームワークとして最も人気のあるExpress用のApollo Serverパッケージです。既存のExpressサーバーにGraphQLサーバーをアタッチすることが可能です。
Choosing an Apollo Server package - Apollo GraphQL Docs より引用
ここまで出来たらGraphQLのコードと合わせてindex.tsを書き換えていきます。
GraphQLのコードに関しては「もしGoogle Cloud Functionsにデプロイするなら」という記事で紹介されているexampleコードを使わせてもらいます
Deploying with Google Cloud Functions - Apollo GraphQL Docs
import * as functions from "firebase-functions";
import express from "express";
import {ApolloServer, gql} from "apollo-server-express";
const typeDefs = gql`
type Query {
hello: String
}
`;
const resolvers = {
Query: {
hello: () => "Hello world!",
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
const app = express();
server.start().then(() => {
server.applyMiddleware({app, path: "/"});
});
export const graphql = functions.https.onRequest(app);
- typeDefsからnew ApolloServerまでのところがApollo Serverの設定
- const appからapplyMiddlewareまでの流れがexpressとApollo Serverを統合しているところ
- 最後の1行でfirebase functionsで使えるようにしています
最後にtsconfig.jsonに2行追記します
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
}
}
allowSyntheticDefaultImports
はESLint対策(ないとexpressのimportで怒られる)esModuleInterop
はビルドにコケる対策になりますTypeError: express_1.default is not a function
というエラーが出力されるのを解消
esModuleInteropは以下の記事を参考にさせていただきましたmm
ExpressでTypeError: express_1.default is not a function エラーの解消方法 - code-log
ここまで出来たらいよいよです!
$ yarn run serve
・・・
✔ functions[us-central1-graphql]: http function initialized (http://localhost:5001/xxxxxx/us-central1/graphql).
・・・
http://localhost:5001 からはじまるサイトにアクセスすると、
Apollo Studioが立ち上がってQueryで定義したhelloが確認出来ました!
Cloud Functions for Firebaseにデプロイする
Cloud Functions for Firebaseを利用するためには無料プランのSparkから従量制プランのBlazeに変更する必要があります。
大量に通信しなければ無料で使えますが、場合によってはお金が発生する可能性が出てきます。
まずfirebaseのページ > 設定 > 使用量と請求額ページ よりプランを変更します
SparkからBlazeへ!
これでFirebase側の設定は出来たので後はデプロイするだけ。
デプロイコマンドも最初から用意されているので非常に簡単でyarn run deploy
を実行するだけ!!
$ yarn run deploy
・・・
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/xxxxx/overview
Cloud Functions for Firebaseに関数が作成されています
デプロイされたGraphQLはアクセスしてもApollo Studioが起動しないためcurlコマンドで確認します
$ curl -X POST -H "Content-Type: application/json" \
-d "{ \"query\": \"query { hello }\"}" https://us-central1-xxxx.cloudfunctions.net/graphql
{"data":{"hello":"Hello world!"}}
無事「Hello world!」が出力されました!デプロイ完了です!