RubyでオレオレWebフレームワークを作っているのですが、だいぶ形になってきたので知識の整理がてら色々まとめてみる✍
今回は第3回目です🤟
👇第2回 GETに対応したRouting機能を作る🛣はこちら https://madogiwa0124.hatenablog.com/entry/2019/09/01/233842
今回のゴール
前回は、GET
リクエストに対応したRouting機能を作りましたが、それをクエリ文字列を受け取れるように修正します👩💻
下記のように定義したら/hello?word="hoge"
にアクセス時に'Hello hoge.'
が表示出来るような機能を作ります。
require_relative './lib/main.rb' router.get '/hello' do |params| "Hello #{params['word']}." end
太字で記載したようにリクエスト時にクエリ文字列を追加で取得し、routeで定義したProcオブジェクトを実行する際に引数として渡します📦
- WEBrickからリクエスト(URL、METHOD、クエリ文字列)取得
app
でmain
で定義したDSLを使って作成したrouter
で管理しているroutingをリクエストのURLとMETHODから探索- 見つかったroutingのProcオブジェクトを返却
application
でProcオブジェクトの引数にクエリ文字列を渡して実行- 結果からレスポンスを生成
- WEBrickにレスポンスを返却
まずはリクエスト時にクエリ文字列を取得する。
まずはリクエストからURLに設定されたクエリ文字列を取得していきます。
application.rb
でそのまま実装してもいいのですが、処理が結構多くなってきたのでRack::Request
を継承した独自クラスを作ってそちらに実装していきます👩💻
👇実装はこんな感じ、env
を引数でとってurl
、method
、query
を設定する処理とクエリ文字列で渡された値を返却するparams
メソッドを追加しています🙋
require 'rack' class MyRequest < Rack::Request def initialize(env) super @url = env['REQUEST_URI'] @method = env['REQUEST_METHOD'] @query = URI.parse(url).query end def params return unless query @params ||= Hash[URI.decode_www_form(query)] end attr_reader :url, :method, :query end
rubyの標準ライブラリのURI
を使うとURI.parse(url).query
でクエリ文字列部分が取得出来て、URI.decode_www_form
の結果をHashの引数で渡すと簡単にHash形式で取得出来るので便利ですね✨
👇実際にapplication.rb
に組み込んだ形がこちら
require 'my_request.rb' require 'rack' class Application def initialize(router:) @router = router end attr_reader :router, :request def call(env) @request = MyRequest.new(env) body = router.bind(url: request.url, method: request.method).process.call ['200', {'Content-Type' => 'text/html'}, [body]] end def run! Rack::Handler::WEBrick.run self end end
RoutingのProcオブジェクトにクエリ文字列を渡す
リクエストに設定されたクエリ文字列を取得出来るようになったので、今度はそれをroutingで定義したProcオブジェクトに渡していきます🙋
これは簡単で単純にcall
の引数にrequest.params
を渡すだけです👍
require 'my_request.rb' require 'rack' class Application def initialize(router:) @request = MyRequest.new(env) @router = router end attr_reader :router, :request def call(env) body = router.bind(url: request.url, method: request.method).process.call(request.params) ['200', {'Content-Type' => 'text/html'}, [body]] end def run! Rack::Handler::WEBrick.run self end end
これで下記のようなroutingを定義してhttp://localhost:8080/hello?word=hoge
にアクセスすると、、、
router.get '/hello' do |params| "Hello #{params['word']}" end
無事にクエリ文字列が反映されました🙌
おわりに
今回はクエリ文字列を含んだGETに対応したRouting機能を作りました👩💻
ここまで出来ると文字列のみを返すような静的サイトだったらなんとか実現できるぐらいには出来てきましたね👍
次回はViewのレンダリング処理を実装していこうかなと思います 🙋♀️ レンダリングが出来るとちょっとフレームワークっぽくなってきた感じがしますね✨