パラボラアンテナと星の日記

あることないこと

serverlessフレームワークでGraphQLのエンドポイントを提供する実例、serverless-graphql-blogを触ってみた

先日2016/2/1、serverlessからこういう記事が出てました。

Serverless GraphQL - Kevin Old | Full-Stack JavaScript Engineer | React.js | Node.js

From conception of the idea of Serverless GraphQL a few weeks ago, to the reference implementation of Serverless GraphQL Blog I have spent less than $1 on AWS resources and only a few hours implementing.

serverless-graphql-blog なる、serverlessフレームワーク上でGraphQLを用いたブログシステムを作ったから見てみなよ!とのことです。

github.com

どんなん?

まずserverlessとは、AWS LambdaAWS API Gatewayを利用してサーバレスでスケールしやすいエンドポイントを作れるフレームワークです。github上で6,000個以上スターが付いています。

今回のserverless-graphql-blog は、その上でGraphQLを提供する実例のようなもの(reference implementationと言っているようだが)です。

先述のこの記事で詳しく紹介されてる。

(私には)早すぎた

で、動かすにあたり、NodeもLambdaも大初心者の私がハマりましたので以下に記録しておきます(2016/2/7)。

Node大初心者なので間違っている部分は多々あると思いますので、そっと教えて下さい、。。

各バージョンとか

$ node -v; npm -v
v5.4.1
3.3.12
$ npm list | grep serv
serverless-graphql-blog@0.0.1 /[省略]/serverless-graphql-blog
├─┬ serverless-helpers-js@0.0.3
└─┬ serverless-optimizer-plugin@1.0.0

動いた手順とか試行錯誤過程

gitで言うとこのへんのバージョンのREADMEを読みました。

読んだところ、以下の手順でやればよさ気な感じです。

  1. $ npm install serverless -g
  2. $ serverless project install serverless-graphql-blog
  3. $ serverless dash deploy

以下適宜メモを入れていきます。

$ npm install serverless -g

グローバルにserverlessパッケージが入ります。 これは特にハマりませんでした。

$ serverless project install serverless-graphql-blog

カレントディレクトリの下にserverless-graphql-blogが展開されます。

展開されたあとに 以下のかっこいい感じ でウィザードが始まります。

$ serverless project install serverless-graphql-blog

Serverless: Installing Serverless Project "serverless-graphql-blog"...
Serverless: Downloading project and installing dependencies...
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v0.3.1
`-------'

Serverless: Initializing Serverless Project...

いろいろ対話的に聞かれますので入力していく。

Serverless: Enter a universally unique project bucket name:  (serverless-graphql-blog-ae1ue6-gutlvy.com)
Serverless: Enter an email to use for AWS alarms:  (me@serverless-graphql-blog-ae1ue6.com)
Serverless: Enter the ACCESS KEY ID for your Admin AWS IAM User:  
Serverless: Enter the SECRET ACCESS KEY for your Admin AWS IAM User:  

Lambda functionなどを配置するバケット、アラーム用のEmailの設定、 AWSのアクセスキー、AWSのSECRET ACCESS KEYなどを入力します。

~/.aws/credentials にファイルが在る人は、アクセスキー等に関してはそのプロファイルが使われるかもしれません。

serverlessのドキュメント内のベストプラクティスを読むと、 「AdministratorAccessを持つユーザの情報を与えるべきでなく、最大でもPowerUserAccessにしてください」とのことでした。 今回私はPowerUserAccessポリシーを持つユーザを一時的に作り、キー等を入力しました。

Serverless: Select a region for your project:
  > us-east-1
    us-west-2
    eu-west-1
    ap-northeast-1

次にリージョンですが、ap-northeast-1(東京)が選択できるのですが、東京だとなぜかS3のバケット作成に失敗する( バケットの文字数制限に引っかかってる気がする… )ので、 us-east-1(バージニア北部)を選択しました。

Serverless: Creating stage "dev"...
Serverless: Creating region "us-east-1" in stage "dev"...
Serverless: Creating your project bucket on S3: serverless.us-east-1.serverless-graphql-blog-ae1ue6-gutlvy.com...
Serverless: Deploying resources to stage "dev" in region "us-east-1" via Cloudformation (~3 minutes)...

ここまで問題なくうまくいくと、 Cloud Formationが走ります。

Cloud Formationと言うと、一気にオオゴト感が増した気がしますが、気にしない方向で行きましょう。

$ serverless dash deploy

次に上記のコマンドですが、これは$ cd serverless-graphql-blog してからじゃないと動きません。

そのへんは空気嫁という感じでしょうか、、

$ serverless dash deploy
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v0.3.1
`-------'

Use the <up>, <down>, <pageup>, <pagedown>, <home>, and <end> keys to navigate.
Press <enter> to select/deselect, or <space> to select/deselect and move down.
Press <ctrl> + <enter> to immediately deploy selected.


Serverless: Select the assets you wish to deploy:
    blog - resource - graphql
      function - blog/resource/graphql
      endpoint - blog/resource/graphql@resource/graphql~POST
    - - - - -
  > Deploy

Serverless: Deploying functions in "dev" to the following regions: us-east-1
Serverless: ------------------------
Serverless: Successfully deployed functions in "dev" to the following regions:
Serverless: us-east-1 ------------------------
Serverless:   blog/resource/graphql: arn:aws:lambda:us-east-1:70000000000:function:serverless-graphql-blog-blog-resource-graphql:dev

Serverless: Deploying endpoints in "dev" to the following regions: us-east-1
Serverless: Successfully deployed endpoints in "dev" to the following regions:
Serverless: us-east-1 ------------------------
Serverless:   POST - resource/graphql - https://xxxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/resource/graphql

実行して成功した場合は上記のような出力となります。途中でfunctionendpointどちらを(または両方を)デプロイするか、ということを選択できます。

ここでは以下の点にハマりました。

_meta/variables/s-variables-dev-useast1.json に追加の情報が必要

blog/resource/graphql: Missing required key 'Role' in params という謎のエラーが出てしまいます。

似たような事象を参考に解決しました。

_meta/variables/s-variables-dev-useast1.json の中身を変えればいいようです。以下のように編集した。

before
{
  "region": "us-east-1"
}
after
{
  "region": "us-east-1",
  "apiGatewayApi": "serverless-graphql-blog",
  "iamRoleArnLambda": "arn:aws:iam::7000000000:role/lambda_basic_execution"
}

arn...lambda_basic_execution の部分は適当にIAMでlambda用のロールを作っておきます。

今回はLambda君がDynamoに触れるようにする必要があります。以下の様なポリシーでいけました。過不足ないかは未確認。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Sid": "Stmt1428000000017",
            "Action": [
                "dynamodb:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:UpdateItem"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

モジュールをnpm installする必要あった

以上でデプロイ完了です。

ので、curlすればレスポンスが返ってくるのですが、

{"errorMessage":"Cannot find module 'serverless-helpers-js'","errorType":"Error"...

とかいうエラーメッセージが返ってきてしまいます。どうやら必要なmoduleがLambdaの中に入れられていないようでした。

このへん、Herokuとかの感覚でやるとうまくいかないものですね。。。

--- a/package.json
+++ b/package.json
@@ -12,7 +12,10 @@
   "dependencies": {
     "babel-preset-es2015": "^6.3.13",
     "babelify": "^7.2.0",
-    "serverless-optimizer-plugin": "^1.0.0"
+    "graphql": "^0.4.16",
+    "graphql-custom-types": "^0.2.0",
+    "serverless-optimizer-plugin": "^1.0.0",
+    "serverless-helpers-js": "^0.0.3"
   },
   "description": "A Serverless GraphQL blog.",
   "devDependencies": {},

バージョンがこれでいいのかはわかりませんが、こうやっておいて npm i し、deployすると動きました。 これでいいんだろうか。

とりあえずおわり!

あとはREADMEに書いてあるようなcurlコマンドで、GraphQLを楽しむことが出来ます。

例:

DynamoDB上のauthorsテーブル:

f:id:hoppie:20160207170803p:plain

クエリ投げる/返ってくる:

$ curl -s -XPOST -d '{"query": "{ authors { id, name } }"}' \
https://randamunamoji.execute-api.us-east-1.amazonaws.com/dev/resource/graphql | jq .
{
  "data": {
    "authors": [
      {
        "id": "2",
        "name": "mitsuo"
      },
      {
        "id": "1",
        "name": "senda"
      }
    ]
  }
}

まとめ

今の時代、一家に一台、フルスタックnodeエンジニア がいれば、サーバレスで高可用なGraphQLエンドポイントが簡単に手に入るようです。