grape で URI パラメータとしてメールアドレスを受け取る

f:id:masm11:20210109214927p:plain

明けましておめでとうございます。masm11 です。今年もよろしくお願いします!

grape をご存知でしょうか? Rails で API を作る時に便利ですね。

今回は、grape を使った API で URI パラメータとしてメールアドレスを受け取ろうと してハマったので、ご紹介します。

環境を用意する

まず Rails 環境を用意します。

gem install rails
mkdir t2
cd t2
rails new .
echo "gem 'grape'" >> Gemfile
bundle install --path=vendor/bundle
bundle exec rails webpacker:install

grape を組み込んでいきます。

まずはルーティングから。

vi config/routes.rb
Rails.application.routes.draw do
  mount Test::API => '/'
end

API の実装を作成します。

vi app/api/test/api.rb
class Test::API < Grape::API
  version 'v1', using: :path
  format :json
  content_type :json, 'application/json'
  prefix :api

  resource '/test' do
    get '/:id' do
      { value: params[:id] }
    end
  end
end

ここではとりあえず URI パラメータとして :id を受け取るようにしてあります。

api の大文字が Api でなく API になるように設定します。

vi config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym 'API'
end

では起動してみます。

bundle exec rails s

API のエンドポイントは http://localhost:3000/api/v1/test/:id です。 ここにアクセスしてみます。

luna:~ % curl http://localhost:3000/api/v1/test/123
{"value":"123"}
luna:~ %

:id が受け取れていますね。

メールアドレスを受け取る

ではメールアドレスを受け取るように改造します。

vi app/api/test/api.rb
class Test::API < Grape::API
  version 'v1', using: :path
  format :json
  content_type :json, 'application/json'
  prefix :api

  resource '/test' do
    get '/:email' do
      { value: params[:email] }
    end
  end
end

params のキーが変わっただけですね。

先ほどと同様に curl でアクセスしてみます。

luna:~ % curl http://localhost:3000/api/v1/test/foo@example.jp
{"value":"foo@example"}
luna:~ % 

なんと .jp が消えています。

他のメールアドレスでも試してみます。

luna:~ % curl http://localhost:3000/api/v1/test/foo@example.co.jp

この場合は RoutingError になりました。

解決策

いろいろなメールアドレスで試してみたところ、拡張子として認識されている のでは、と思い至りました。 Rails は URL の末尾に .html とか .json とかを付けて、希望する レスポンス形式を指定する機能がありますよね。 あれが効いているのでは、ということです。

api.rb の get の行を以下のように変更します。

    get '/:email', requirements: { email: /.*/ } do

このように変更したところ、正しく受け取ることができました!

luna:~ % curl http://localhost:3000/api/v1/test/foo@example.co.jp
{"value":"foo@example.co.jp"}
luna:~ %