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

あることないこと

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エンドポイントが簡単に手に入るようです。

【Go初心者】麻雀のあがり判定をRubyで書いたやつをGoで書きなおしてみた、そして多少のvimrc追加

天和あがれるやつをGoで書きなおしてみました。

f:id:hoppie:20160103103539g:plain

処理速度は超早くなりました。当社比2000%。

成長の記録(のびしろですね!)。

github.com

Go書くのは人生初です。

CもJavaも書いたことなくて、rubyしか書いたことないのですが、

forとifさえあればなんとかなるという感じでやった。後悔はしていない。

インターフェースとか書けるのが嬉しいらしいっぽい、時間あるときに学びたい。

以下、初心者がGoはじめるにあたり環境周りでやったことなど。

vim周り1

golang vimrcでググッて適当に調べただけで、べんりなものがあった。

.vimrcへ以下を追記。 事前にnsf/gocodeをgo getしておく。

+
+" http://qiita.com/uchiko/items/4c186292f007535116cc
+filetype off
+filetype plugin indent off
+" set runtimepath+=$GOROOT/misc/vim
+filetype plugin indent on
+syntax on
+autocmd FileType go autocmd BufWritePre <buffer> Fmt
+exe "set rtp+=".globpath($GOPATH, "src/github.com/nsf/gocode/vim")
+set completeopt=menu,preview

vim周り2

golangといえばハードタブ。

私のvimrcではC-iはソフトタブが挿入されちゃう感じだったので、拡張子で判断できるように変更。

+
+" http://blog.restartr.com/2014/04/20/vimrc-noexpandtab-in-golang/
+if expand("%:t") =~ ".*\.go"
+  set noexpandtab
+  set tabstop=4
+  set shiftwidth=4
+endif

以上2つの変更で、:wで保存した時に自動的にgo fmt的なのが走る感じになる。

go、pythonなんて比じゃないぐらい固い言語という印象を持った。

Go書けるようになりたい!

いまのところまだよくわかってないところ箇条書き:

  • なぞの「interface」
    • ダックタイピングできるらしい
  • なぞの「goroutine」
    • 並列処理書きたい
  • テスト
    • テストフレームワークがないのはわかった、どういう感じで書くのがいいんだろう

麻雀のあがり判定をゼロから書いて、天和コマンドを作ってみた

【車輪】麻雀のあがり判定をゼロから書いて、天和コマンドを作ってみた感想【再発明】

プログラミングの話ですが、麻雀の話です。

$ tenho ってコマンドを打つと天和がアガれたら面白いんじゃないかと思って、作った

うごくやつができた

こんなん

f:id:hoppie:20151231170016g:plain

なぜそんなことを

ruby -e "puts '🀀'.next"
=> "🀁"

みたいに文字が使えるし、CLIでも見栄えが良いかなと思ってた。

休日の車輪の再発明にはちょうど良さそう。

ロジックの方はおみくじ感覚でかんたんにできるかなと思ってた。

が、あがり判定っていうのはわりと難易度高かった。。

ロジックとか感想とか

以降、だらだらと感想とか書く。

$ tenhoの動き自体は、

  1. (34 * 4)のカード(牌)の束からランダムに14枚を取り出す。
  2. それがアガっていれば終了。上がっていなければもう一度14枚取り出す

という感じ。

ランダムに14枚取り出すのはArray#sample的なものが使った(あ、rubyっす)。

やはりあがり判定がキーになる。

適当に書いた感じでも、1秒間に1500回以上のサンプリングとあがり判定ができたっぽい。意外と速くて満足してしまった : )。

それでも感覚的には天和上がるには200万回ぐらい必要(本当の確率は調べてない。。)なので、数分必要なのだが。。

自分が書く上でポイントだと思ったこと3つ。

3つのあがり系

周知の通り麻雀には3つのあがり形があって(すくなくとも天和の場合はこの3つでいいと思う)

というかんじになる。ここに気づくのがポイント。

スート

スート(トランプでいうところのハート・ダイヤ・クラブ・スペード)が4種類(萬・筒・索・字)。

字牌だけは、順子が作れないという特徴がある。

別のスート同士で順子や刻子や対子は構成できないので、必然的にカードをスート毎にグルーピングする必要が出てくる。

テスト書きながら書くと楽

こういうときのテストは書いてて楽しい

書きながら思ったこと

七対子だるいwwwww

七対子をどこで判定するかがだるい。

たとえば索子が8枚あるということがわかっているとき、それは(3+3+2)形でなかったとしても(2+2+2+2)形かもしれない。

七対子の判定の順序は、最初のほうにしたほうがパフォーマンスが良いかもしれない。

順子と刻子

順子と刻子の判定については難しいかなと思ってたら、そうでもなかった。

三連刻のかたち(444555666とか)の判定は、役を解釈しないかぎり(天和だけを考慮する場合)は気にしなくて良いので。

同様に役を解釈しないかぎりにおいては、七対子二盃口か、みたいな判定も要らない。

今後書きたいこと

書いてると無性にオプション作りたくなる。いま思いついたのは以下。センス☓。

  • --[no-]normal ノーマル型(33332型)を除外
  • --[no-]chi-toitsu 七対子を除外
  • --[no-]kokushi 国士無双を除外
  • --limit [arg] リミットを指定
  • --sanma サンマモード

あと他の言語で書いても面白いかもしれないと思ってる