Crystalで実装したHTTPサーバーをHerokuにデプロイする
Crystal書いたこと無いけど,やってみる.試行錯誤のログ.ちなみに,Rubyは書けない.
ここをfmfmと言いながら読んでみたくらい.
インストール
macOSだとHomebrewで入る.
$ brew update $ brew install crystal-lang
プロジェクト作成
$ crystal init app crystal-sample-http-server create crystal-sample-http-server/.gitignore create crystal-sample-http-server/LICENSE create crystal-sample-http-server/README.md create crystal-sample-http-server/.travis.yml create crystal-sample-http-server/shard.yml create crystal-sample-http-server/src/crystal-sample-http-server.cr create crystal-sample-http-server/src/crystal-sample-http-server/version.cr create crystal-sample-http-server/spec/spec_helper.cr create crystal-sample-http-server/spec/crystal-sample-http-server_spec.cr Initialized empty Git repository in /Users/upamune/src/github.com/upamune/crystal-sample-http-server/.git/
これでプロジェクト作成できる.今っぽい.
.travis.yml
まで生成されるのか.
ディレクトリ構成がGoなのは気にしない.
HTTPサーバー実装
/
に来たら, 200 OK
の Hello, Crystal
というレスポンスを返すHTTPサーバーを標準ライブラリで実装してみる.
標準ライブラリのドキュメントはここを見れば良さそう.
README - github.com/crystal-lang/crystal
ドキュメントのバージョンと利用しているCrystalのバージョンがあっているか注意.
$ crystal verion Crystal 0.19.2 (2016-09-16)
HTTP - github.com/crystal-lang/crystal
おそらくココらへんに何か書いてそう.
HTTP::Server - github.com/crystal-lang/crystal
これか.
require "http/server" ... server = HTTP::Server.new("0.0.0.0", port, [ HTTP::ErrorHandler.new, HTTP::LogHandler.new, ]) do |context| context.response.content_type = "text/plain" context.response.status_code = 200 context.response.print "Hello world!" end puts "Listening on http://0.0.0.0:8080" server.listen
参考にして書いてみた.ログを出すようにミドルウェアを追加しておいた.
HTTP::Server::Response - github.com/crystal-lang/crystal
ステータスコードはこれでいじれる. HTTP::Server::Response#status_code - github.com/crystal-lang/crystal
デフォルトが 200
なので,今回はいじらなくて良いけど,明示的に書いておく.
これで必要な処理は書いた気がするので,走らせてみる.
$ crystal build src/crystal-sample-http-server.cr $ ./crystal-sample-http-server Listening on http://0.0.0.0:8080 $ http localhost:8080/ HTTP/1.1 200 OK Connection: keep-alive Content-Length: 15 Content-Type: text/plain Hello, Crystal.
おお.動いた. build
サブコマンドは o
オプションで吐き出すバイナリの名前を変更できる.あと, 本番時は --release
を付けてビルドするらしい.
大体できたけど, /
だけ200
を返して,他は404
返すようにしたい.ルーティングどうやんだろ.
request
からパスが取れるっぽいのでそれを使ってマッチさせる.
HTTP::Request#path - github.com/crystal-lang/crystal
server = HTTP::Server.new("0.0.0.0", port, [ HTTP::ErrorHandler.new, HTTP::LogHandler.new, ]) do |context| case context.request.path when "/" context.response.content_type = "text/plain" context.response.status_code = 200 context.response.print "Hello, Crystal." else context.response.status_code = 404 end end
一応これでクソ雑ルーティングっぽいものはできた.
$ http localhost:8080/ HTTP/1.1 200 OK Connection: keep-alive Content-Length: 15 Content-Type: text/plain Hello, Crystal. $ http localhost:8080/hoge HTTP/1.1 404 Not Found Connection: keep-alive Content-Length: 0
よしよし.
後でググったら,Sinatraっぽくやってるのもあった.
ハッシュにパスとそれに対応するProcを登録していく感じ.
一応動くようにはなったので,Herokuにデプロイしていく.
Herokuにデプロイするための準備
公式のビルドパックはないので,これを利用する.
crystal-lang/heroku-buildpack-crystal: Heroku buildpack for Crystal
最新のバージョンのCrystalを利用して動くらしいが, .crystal-version
がプロジェクトのルートにあると,そこに記述されているバージョンを利用するらしい.
準備としてはもう一つあって, このビルドパックが,アプリケーションを走らせるときに --port
でポート番号を指定してきているので,このオプションに対応する必要があるので,少し追加する.
OptionParser - github.com/crystal-lang/crystal
ここを読んでみる.
require "option_parser" ... port = 8080 OptionParser.parse! do |parser| parser.on("-p PORT", "--port=PORT", "Specifies the port") { |port_str| port = port_str.to_i if port_str.to_i? } end
こんな感じで,一応ポート番号をオプションで指定できるようになったのでこれで良さそう.
準備ができたので,デプロイしてみる.
Herokuにデプロイ
$ heroku create crystal-sample-http-server --buildpack https://github.com/crystal-lang/heroku-buildpack-crystal.git $ git push heroku master $ heroku open
オ,ちゃんと表示されてる.
$ http https://crystal-sample-http-server.herokuapp.com/ HTTP/1.1 200 OK Connection: keep-alive Content-Length: 15 Content-Type: text/plain Date: Thu, 22 Sep 2016 15:12:05 GMT Server: Cowboy Via: 1.1 vegur Hello, Crystal. $ http https://crystal-sample-http-server.herokuapp.com/hoge HTTP/1.1 404 Not Found Connection: keep-alive Content-Length: 0 Date: Thu, 22 Sep 2016 15:12:08 GMT Server: Cowboy Via: 1.1 vegur
良い.
まぁ普通はWAFを利用するんだけど,有名どころだと,このへんなのかな?
更新もされている.Sinatraとの比較が載っているけど,まぁ速い.
サイトもちゃんとある.
これも触って,試してみたい.
ちなみに今回のやつは👇に置いてある.