【Ruby】Sinatraでファイルが大きくなったので分割する

皆さん、Sinatra使っていますか?
簡単なWebアプリであれば一瞬でできてしまうような、Webアプリケーションフレームワークです。

しかし、簡単なので機能をたくさん増やしていたり、処理が多くなってくるとどうしても起こるのが「全体像が見えにくくなる」ということ。
機能やエンドポイントごとに分割したい、と思うこともあるでしょう。
私は思いました。
その方法を調べてみたので、まとめておきます。

例として、以下のような形でアプリケーションを作成しているとします。

[ruby]
# app.rb
require 'sinatra’
class MyApp < Sinatra::Application
get '/’ do
'hello’
end
end
[/ruby]

今回は、エンドポイントごとにファイルを分割していきます。

 


 

例1:API用のパスを作成する

追加実装する機能として、APIを作ることになったのでAPI用のURLを作成することになったとしましょう。
まず考えるのは「ブラウザ等からアクセスするパスとAPIとを分離したい」ということでしょうか。

簡単な方法としては「namespace」を使う場合です。
Sinatra::Namespace (part of Sinatra::Contrib)

[ruby]
# app.rb
require 'sinatra’
require 'sinatra/namespace’ # namespaceを使うためのGem

class MyApp < Sinatra::Application
  namespace '/api’ do
    get '/hoge’ do
      # /api/hogeでアクセス可能
    end
  end

  get '/’ do
    'hello’ # 変わらず/でアクセスできる
  end
end
[/ruby]

機能ごとにnamespaceで区切ることで、機能を分けやすくなりました。
なお、namespaceは入れ子にすることができます。

[ruby]
namespace '/api’ do
  namespace '/v0’ do
    get '/getScore’ do
      # /api/v0/getScoreでアクセス可能
    end
  end
end
[/ruby]

例2:機能の新旧バージョン混在

開発が進んでくると、APIや既存のパス以外に新しい処理やパスが増えていきます。
それに伴って、新しい機能と互換性のために古い機能を混在させなければいけないこともあります。
個人で作る場合も、スマホアプリとかではOSのバージョンによって使えたり使えなくなったりする機能とかで必要になるかも?わからんけど。

このような状態だと、namespaceで区切ってもファイルが大きくなってしまい、よくわからなくなってしまいます。
そこで、(タイトルにもありますが)思い切ってファイルごと分割してみます。

ドンピシャな内容が、stackoverflowに上がっていました。
ruby – Using Sinatra for larger projects via multiple files – Stack Overflow

[ruby]
# main_app.rb
require 'sinatra’
require 'sinatra/namespace’

# 別ファイルに分割したAPIを一括で読み込む
require_relative 'routes/init’

class MyApp < Sinatra::Application
  # メインとなるアプリ自体に設定を書いておくと立ち位置を分けやすい

  get '/’ do
    'hello’
  end
end
[/ruby]

[ruby]
# routes/init.rb
require_relative './old_api’
require_relative './new_api’
[/ruby]

[ruby]
# routes/old_api.rb
class MyApp < Sinatra::Application
  namespace ’/api/v0′ do
    get '/’ do
      'api v0′
    end
  end
end
[/ruby]

[ruby]
# routes/new_api.rb
class MyApp < Sinatra::Application
  namespace ’/api/v1’ do
    get '/’ do
       'api v1’
     end
   end
end
[/ruby]

これによって、新旧APIが共存した状態を作れました。
また、ファイルが分かれているので必要ないところに気にせずに作業ができますね。
(一括変換で、余計な記述を書き換えてしまったりするリスクが減ります。やったね。)

肝としては、分割したファイルをroutes/init.rbで一括で読み込んでいるところですね。
これにより、それぞれのファイルは独立しているような形で記述することができます。
もちろんすべてMyAppというクラスなので、全体で使うような処理やインスタンス変数は共有されています。
DB関連のクライアントオブジェクトなどは、メインとなるファイル側でinitializeしておき、@clientなどとして宣言しておけば、ほかのファイルからも参照できるわけですね。
便利。

こんな感じで、Sinatraのファイルを分割する方法でした。
Rubyさんは、クラスを開いて機能追加が簡単にできるので便利です。

 

まとめ

今回は、Sinatraを使った簡単なクラスの分割方法を確認しました。
この方法は、特に2つ目の例はSinatraに限らず使うことができる方法だと思います。

 

今回は、ここまで。
おわり