Posted at
mrubyDay 19

mrubyでyamlを読みこんでh2oが返す

More than 1 year has passed since last update.


h2oとmruby

ある日、

「h2oとmruby使ったらhtmlがなくてもresponse返せるんじゃないか?」

と思ったので、やってみることにしました。


mrubyでどのように返すデータを持つか

さて、responseの内容をmruby scriptの中にベタ書きするのはカッコ悪そうなので、yamlに記述して、外部から読みこむことにします。


h2oの用意

ひとまず、mrubyで簡単なresponseを返すh2oを用意します。


Dockerfile

FROM unasuke/h2o-alpine:v2.0.4

COPY . /etc/h2o
CMD ["h2o", "--mode=master", "-c", "h2o.conf"]



h2o.conf

listen: 80

hosts:
"127.0.0.1:80":
paths:
"/":
mruby.handler-file: server.rb
access-log: /dev/stdout


server.rb

class Server

def call(env)
[200,
{
"content-type" => "text/plain; charset=utf-8",
},
["Hello mruby in h2o!"]
]
end
end

Server.new


Create simple server · unasuke/mruby_ac2016@27cf7eb

# buildしてrun

% docker build -t h2o_mruby .
%
docker run -it -p 8080:80 h2o_mruby

すると、このように8080番ポートでアクセスできるようになりました。mrubyがresponseを返しているのがわかります。

response from server.rb


mrubyがyamlを読みこむために

mruby scriptの中でyamlを読みこむためには、AndrewBelt/mruby-yamlを使う必要があります。が、このmrbgemは素のh2oには含まれていないので、mruby-yamlを含んだh2oをbuildしなくてはいけません。

そこで、そのようなh2oを用意しました。

unasuke/h2o at mruby-yaml

用意といっても簡単で、deps 以下にmruby-yamlをcloneしてくるだけです。

そして、Dockerfileを次のように変更して、h2oをbuildします。


Dockerfile

FROM alpine

RUN apk add --no-cache --virtual=builddeps \
bison \
ca-certificates \
cmake \
curl \
gcc \
git \
g++ \
libc-dev \
linux-headers \
make \
openssl \
perl \
ruby \
ruby-dev \
wget \
yaml-dev \
zlib-dev \
&& git clone https://github.com/unasuke/h2o.git \
&& cd h2o \
&& git checkout mruby-yaml \
&& cmake -DWITH_BUNDLED_SSL=on -DWITH_MRUBY=on . \
&& make install \
&& cd .. \
&& rm -rf h2o-* \
&& apk del builddeps \
&& apk add --no-cache --virtual=rundeps \
libstdc++ \
perl

RUN mkdir /etc/h2o

WORKDIR /etc/h2o

EXPOSE 80 443

COPY . /etc/h2o
CMD ["h2o", "--mode=master", "-c", "h2o.conf"]


Build h2o with mruby-yaml · unasuke/mruby_ac2016@4a3c552


yamlを読む

いろいろ準備が整ったので、yamlを読みこんでresponseを返していきます。

このようなyamlを用意しました。


data.yml

responses:

-
path: "/"
message: "index"
-
path: "/hoge"
message: "hoge"
-
path: "/fuga"
message: "fuga"

そして、その内容に従ってresponseを返すように、mruby scriptを次のように書きかえます。


server.rb

class Server

def call(env)
response = fetch_response env['PATH_INFO']
if response
[200,
{
"content-type" => "text/plain; charset=utf-8",
},
[response]
]
else
[404,
{
"content-type" => "text/plain; charset=utf-8",
},
["Not found"]
]
end
end

def fetch_response(path)
yaml = YAML.load(File.open('data.yml').read)
message = nil
yaml['responses'].each do |res|
if res['path'] == path
message = res['message']
end
end
message
end
end

Server.new


Return response from yaml · unasuke/mruby_ac2016@125a17b

docker buildしてrunすると、このようにyamlの内容に従ってresponseが返ってくるようになりました。

localhost:8080/

localhost:8080/hoge


余談

本当はhaconiwaのなかでh2oを動作させたかったのですが、どうにもうまくできず諦めました。