もとの記事は JRuby - FreeStyleWiki
とりあえずJRuby+Hanami+HerokuでREST APIを動かすところまでできたので記事を書いておく。
REST APIを作ってみる
最初の目的であるREST APIを作る
- HanamiによるAPIの作成手順
ほとんどコレの内容を見て作成した。使用するSQLについてはいろいろ変えている。
作りたいもの
- MySQLのお手本テーブルである employees をJSONで出力するやつ
- テーブル定義は → MySQL Sample Databases
Hanami - ドキュメント
- Hanami | Guides - Command Line: Generators
- ここにアクションやルートテーブルの生成用のコマンドが載っている
新規アプリの追加
> jruby -S bundle exec hanami generate app api
新規Action/Viewの追加
> jruby -S bundle exec hanami generate action api employees#list
これで employees というActionができる。ルートテーブルにもいろいろ追加された。
ここまででできていること
- Hanamiの全体設定としてのアプリのURL(マウント)設定
- config/environment.rb に Api アプリケーションのマウント場所が書いてある
つまり、http://{ホスト名}/api 以下にアプリが配置されるということ
Hanami.configure do mount Api::Application, at: '/api' ...
デフォルトではhtmlを返す設定になっているので、API用に以下を追記する
module Api class Application < Hanami::Application configure do # 以下を追加 default_request_format :json default_response_format :json body_parsers :json ...
- employeesのためのコントローラー
- apps/api/controllers/employees/list.rb に employeesを返すためのModuleができている
これの面白いところはコントローラーがメソッドごとに分割されているところだろう
module Api::Controllers::Employees class List include Api::Action accept:json # 追加 def call(params) end end end
これもメソッドごとに分割されている
module Api::Views::Employees class List include Api::View # 以下を追加 layout false def render "[]" end end end
モデルは単数形になることに注意
> jruby -S bundle exec hanami generate model employee
- 元となる理想のテーブル定義(MySQL)
CREATE TABLE employees ( emp_no INT NOT NULL, -- UNSIGNED AUTO_INCREMENT?? birth_date DATE NOT NULL, first_name VARCHAR(14) NOT NULL, last_name VARCHAR(16) NOT NULL, gender VARCHAR(1) NOT NULL, -- Enumeration of either 'M' or 'F' hire_date DATE NOT NULL, PRIMARY KEY (emp_no) -- Index built automatically on primary-key column -- INDEX (first_name) -- INDEX (last_name) );
- 作成されたmigrationファイルを改変する
- db/migrations/YYYYMMDD000000_create_employees.rb
Hanami::Model.migration do change do create_table :employees do primary_key :emp_no, Integer, null: false column :birth_date, Date, null: false column :first_name, String, null: false, size: 14 column :last_name, String, null: false, size: 16 column :gender, String, null: false, size: 1 column :hire_date, Date, null: false end end end
Hanamiのマイグレーションファイルの書き方は、ここに書いてある
そして、実は生のSQLでも実行できる
Hanami::Model.migration do up do execute %{ INSERT INTO `employees` VALUES (10001,'1953-09-02','Georgi','Facello','M','1986-06-26'), (10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21'), (10003,'1959-12-03','Parto','Bamford','M','1986-08-28'), ... } end end
employeeのDBのテーブルを作成
以下の手順でエラーが出たときは、おそらくWindows/Unix間のパスの問題なので .env.development を見る
DATABASE_URL="jdbc:sqlite:db\\generic_dao_jruby_development.sqlite"
- 開発環境はSQLite3で動く、ゼロから始める場合は以下のコマンドでdbファイルを作成
> jruby -S bundle exec hanami db create
- その後以下のコマンドでSQLを実行
> jruby -S bundle exec hanami db migrate
JSONを返す部分を追記
とりあえず、以下の追記でサーバを再起動すればJSONが出力されるはず
- apps/api/controllers/employees/list.rb
class List include Api::Action accept :json + expose :employees def call(params) + @employees = EmployeeRepository.new.all end end end
- apps/api/views/employees/list.rb
module Api::Views::Employees class List include Api::View layout false def render - "[]" + _raw JSON.dump(employees.map{|employee| employee.to_h }) end end end
hanami-modelについての見解
さて、ここまででサーバが起動できるはず
> jruby -S bundle exec hanami s
http://localhost:2300/employee にアクセスするとJSONが返ってくる*2。
Hanamiのすごいところは、ここまででO/Rをマッピングするコードを書いていないところだ。詳しくはhanami-modelのREADMEを見れば良いと思うが、model/README.md at master · hanami/model · GitHub。これは結構すごいと思う。
つまりはDB側でカラムの更新があり、usersテーブルにbirthdayというカラムを追加したとしても特にmodelの側でコードの変更は無いということだ。
Javaのものと比べるとすると、例えばMyBatisだとmapper.xmlの中にDBのカラムとObjectのフィールド要素をマッピングするファイルが必要になる。例えばHibernateだとクラスのフィールドに対してアノテーションを付けまくる必要がある。