読者です 読者をやめる 読者になる 読者になる

Web 上のリソースとその表現

Web

RSpec で request spec を書くとき、get "/users/:id.json" と書くかわりに get "/users/:id" と書くとエラーになりました。

ActionController::UnknownFormat:
  UsersController#show is missing a template for this request format and variant.

リソース /users/:id に対して拡張子で指定しないならば、HTTP リクエストのヘッダに Accept: application/json をつけて、クライアントが利用したいデータ形式を指示する必要があります。

そもそもなぜこういうふうになっているのかを整理しました。

リソース

リソースとは Web 上に存在する情報そのものであり、URI (Uniform Resource Indicator) で指し示せます。たとえば次のようなリソースが考えられます。

  • 人のプロフィール
    • URI 例:http://example.com/users/john
  • ブログ記事
    • URI 例:http://example.com/entries/2017/01/01

わかりやすい URI でリソースを指定することで、どのような情報なのかが人間にとってわかりやすくなります。なお、ここでは、その情報がどのような見た目(表現)になっているかについては言及していません。

また、リソースに対して、HTTP のメソッド (GET, POST, PUT, PATCH, DELETE) を使うことで CRUD をはじめとする各種操作が実行できます。

リソースの「表現」

「表現」という言葉はリソースがどのような形式のデータになって、サーバ/クライアント間で通信されるかを指しています。表現には次のようなものがあります。

  • メディアタイプ
    • HTML, XML, JSON, JPEG, PDF など
  • 言語
    • 日本語、英語、中国語など
  • 文字エンコーディング
    • UTF-8, Shift_JIS など

リソースは複数の「表現」をとれる

あるリソースは次のように複数の「表現」をとりえます。

  • 人のプロフィールが HTML, JSON, PDF で表現できる
  • ブログ記事が日本語、英語で表現できる

リソース表現の指定方法

HTTP を介したサーバとのやりとりにおいて、リソースの表現をどう指定するかについては次のような方法があります。

  • クエリ文字列
    • GET http://example.com/users/john?format=json で人のプロフィールの JSON 表現を得られる
  • 拡張子
    • GET http://example.com/entries/2017/01/01.en でブログ記事の英語表現を得られる
  • コンテントネゴシエーション
    • GET http://example.com/users/john のリクエストヘッダに Accept: application/pdf を利用するとプロフィールの PDF 表現を得られる
    • ほかには Accept-LanguageAccept-Charset など

リソースと表現を分離する利点

リソースと表現の関係を疎にして、リソースが複数の表現をとれるようにすると、さまざまなクライアントが求める形式のデータを統一された HTTP のインタフェースで提供できるようになります。また、拡張性の面でも利点があります。

参考資料

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Rails 5.0.1 で rails new するとできる Gemfile の git_source ブロックの意味

Rails

Rails 5.0.1 で rails new したときに作成される Gemfile の先頭に次のブロックが挿入されるようになっていました。

git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
  "https://github.com/#{repo_name}.git"
end

これの意味

Gemfile の中で :github オプションをつけた gem について、HTTPS 経由で GitHub から取得します。

git_sourceBundler で定義されているメソッド で、引数のオプション(ここでは :github)が付いた gem の取得先 URL をブロック内で指定できます。

やる理由

Bundler が持つ :github オプションは Git プロトコルで通信するのでセキュアでなく、さらに Bundler 1.13 以降は :github オプションを使っていると警告が出ます。公式ドキュメントでも :github オプションを使うのを避けるよう明記してあります。

このコードを入れておくと、HTTPS 経由で GitHub から gem を取得できるので警告が出ずにすみます。ちなみにデフォルトの Gemfile では web-console:github オプションを使っていますね。Bundler 2.0 ではこの点が対策されるようで、それまでの対処ということです。

入ったプルリクはこちらです。

github.com

参考資料

Yokohama.rb Monthly Meetup #76 に参加した

Ruby 日記

2017-01-14(土)の Yokohama.rb Monthly Meetup #76 に参加したので、メモを書きます。1 週間たってしまった。

yokohamarb.doorkeeper.jp

Ruby レシピブック

今回はレシピ 244 から 247 まで読みました。システム寄りの話題が中心です。

レシピ 244

スレッドファイバの扱いかたについてです。

スレッドを使うときに気をつけるべき点は次のようなところでしょう。

  • あるスレッドが別のスレッドの変数を操作しないように、Thread#fork の引数としてスレッド固有のローカル変数を渡す
  • メインスレッドが勝手に終了するのを防ぐため Thread#join でスレッドが終了するのを待つ

ファイバは軽量スレッドのようなものです。スレッドは自動で他スレッドに制御が移りますが、ファイバが持つコードを実行するには Fiber#resume を実行し、制御を呼び出し元に戻すには Fiber#yield を実行する必要があります。Enumerable#each など内部イテレータをジェネレータのような外部イテレータに変換するコードとともに紹介されていました。

ちなみに、Ruby 1.9 以降では組み込みの Enumerator をジェネレータとして使うことができます。

sentence =<<EOF
lorem ipsum
hoge fuga fizz bazz
EOF
enumerator = sentence.each_line  # Enumerator を返す
loop { p enumerator.next }
# => "lorem ipsum\n"
# => "hoge fuga fizz bazz\n"

また、レシピのサンプルコードで Object#__send__ というメソッドが使われていました。これは、send という名前が一般的で再定義されやすいことから定義された Object#send の別名ということです。

レシピ 245

プロセスのフォークについてです。

レシピ内では fork して exec するサンプルコードが紹介されていました。この用途なら Kernel.#spawn でもよいという話がありました。子プロセスの終了を待つなら Process.waitpid2 を使う必要があります。

pid = spawn('job')
exitpid, status = *Process.waitpid2(pid)  # 'job' が終了するまで待つ

レシピ 246

プロセスがシグナルを受けたときの動作を設定するシグナルハンドラについてです。

有名な SIGINT などの他に SIGUSR1, SIGUSR2 というはシグナルがあって、これはユーザ定義用のものだそうです(参照:シグナル (ソフトウェア) - Wikipedia)。

Pry など REPL 上で Singal.trap(:USR1) { puts 'USR1' } などとして、killSIGUSR1 を送ると、シグナルハンドラが動作していることが確かめられます。

レシピ 247

プロセスをデーモン化する方法についてです。

注意点として、デーモンの場合、必ず Kernel.#exit! で終了するようにします。exit!ensure 節など後処理も飛ばしてプロセスを終了します。これを使わないと stdio ライブラリのバッファが 2 回フラッシュされてしまうなどの問題が起きるそうです。

そもそもなぜデーモンなのか? nohup ではだめなのか?という話に展開して、次のページを皆で見ていました。

もくもく

後半はもくもく会でした。僕は swagger-docsSwagger UI を使って、Rails で作った API のドキュメント化を試していました。

懇親会

miyohide さん誕生日おめでとうございました。


次回は 2017-02-18(土)です。次のリンクから申し込めます。

yokohamarb.doorkeeper.jp

冪等な更新処理の API エンドポイントでは PUT を使うとよさそう

API

結論

  • star や like を付与するような、冪等性を持つアクションのための API エンドポイントでも POST はよく使われる
  • が、HTTP メソッドの意図を考慮すると、冪等な更新処理の API エンドポイントにアクセスするときの HTTP メソッドは、POST より PUT がよりよさそう

何をやったか

Twitter の like や GitHub の star を付与するようなアクションを、API エンドポイントとしてどのように表現すればよいのかというのを考えていました。

データを編集する操作なので POST, PUT, PATCH のいずれかで、さらに新規に like を表すリソースを作ると考えると、POST か PUT かなと思いました。この二つのどちらがよさそうか、既存 Web サービスの公開 API を見ながら調べてみました。

調査結果

POST

Twitter や Instagram の like は POST でした。

Twitter だと、リソース favorites/create を POST で作成するエンドポイントとなっています。

POST https://api.twitter.com/1.1/favorites/create.json

データを編集するための HTTP メソッドには POST はよく使われます。今回のような操作でも POST が使われている場合が多いようです。ただ、POST は送信したデータを指定 URI に従属させることを意図しています*1。たとえば

POST /v1/users

users の配下に新しくユーザのリソースを作成するようなパターンです。

なので、Twitter の API のように、直接リソース favorite/create を URI で指定するのは、POST の本来の意図とは若干異なってくるのかなと感じました。

PUT

GitHub API v3 の star は PUT でした。

リポジトリに対する star では、PUT で user が持つ starred/:owner/:repo というリソースを作成するエンドポイントとなっています。

PUT /user/starred/:owner/:repo

また、Gist に対する star では、PUT で star を作成するエンドポイントとなっています。

PUT /gists/:id/star

PUT を使う場合の要件として

  • 冪等性を担保すべき*2
  • URI でリソースを直接指定すべき*3

があります。

よって、次の理由

  • 一般に star や like は一度付与したら何度付与しても増えたりしない(冪等な処理である)
  • リソース (:repostar) を URI 内で直接に指定している

から、今回のようなエンドポイントでは POST よりも適しているのかなと思いました。

参考資料

Web API: The Good Parts

Web API: The Good Parts

次の Qiita 記事がかなり参考になりました。

qiita.com

*1:『Web API: The Good Parts』2.3.2 節参照

*2:http://stackoverflow.com/questions/630453/put-vs-post-in-rest

*3:『Web API: The Good Parts』2.3.3 節参照

2016 年ふりかえり

日記

2016 年をふりかえらないと 2017 年が始まらないので、ハイライトでふりかえります。

上半期と下半期で在籍していた会社が違うので、そのくくりで分けてます。

上半期

個人活動

2015 年の秋ぐらいから触っていた Ruby で引き続き遊んでいました。

読書メーターにある自分の読書記録を自分でハンドリングしたくて、スクレイピング用 gem を作ったりしてました。

github.com

スクレイピングは結構つらいということがわかりました。なんやかんやあって結局ブクログに移行しました。

blog.kymmt.com

また、hatenablog gem や、それを使ったブログ編集用ツールに pull request をいただきました。ありがとうございます!!!

blog.kymmt.com

ほかには、ひとりで Ruby を書いてるだけではなく外に出ないといかんと思い、Yokohama.rb に参加し始めました。なぜ横浜かというと、この当時は横浜市内に住んでいたからです。当たり前なのですが Ruby にとても詳しい方が多く、感動した覚えがあります。また、ここで id:kurotaky さんに出会うのが、この後の伏線になります。

blog.kymmt.com

毎回参加記事を書いていたら、レシピブック読書会まとめマン的役割を若干確立しつつある感じになっています。

インフラ周りに慣れるべく、独自ドメインを取って設定したり、Let's Encrypt で証明書取得して nginx のサーバ設定を書き換えたりもしていました。

blog.kymmt.com

blog.kymmt.com

業務

MS Word と Eclipse を 7:3 ぐらいで使っていた記憶があります。

転職活動

5 月ぐらいに本格的に転職しようという気持ちになって、Yokohama.rb で kurotaky さんから聞いていた GMO ペパボのペパランチョンを思い出し、参加させてもらいました。

pepabo.com

これきっかけでペパボがとてもよさそうという感想に至り、6 月下旬にカラーミーショップのエンジニアとして応募したところ、8 月頭に内定しました。人生なにがあるかわからないですね。

前職は 9 月末で退職、10 月からはペパボ所属となりました。

下半期

ペパボカレッジ

入社後 1 か月かけて、福岡でペパボカレッジという研修を受講しました。詳しくは同期の qkake とともに社のブログにまとめたのでご参照ください。

tech.pepabo.com

業務

カラーミーショップというネットショップ作成サービスを開発しているグループで、カート画面を新しくするプロジェクトに加わって開発作業しています。Rails, PHP, Angular などを使っています。実力的にまだまだで、日々反省点も多いです。粛々とできることを増やしていきたいという気持ち。

個人活動

hatenablog gem の 0.4.0, 0.5.0 をリリースしました。8 月に引き続き、pull request もいただけたので、ありがたかったです。

blog.kymmt.com

blog.kymmt.com

ペパボ福岡支社でペパボカレッジ受講中の 10 月に Fukuoka.rb に参加させていただきました。

blog.kymmt.com

社のアドベントカレンダーに参加して、業務で得た知識を膨らませてアウトプットしてみました。

blog.kymmt.com

所感

アウトプットしたり外に出ていったのが功を奏した 1 年だったように思います。まさか興味本位で Ruby を触りはじめたころに「1 年後に Ruby を書く仕事をやっている」とは思っていなかったというのが本当のところです。

仕事を通じて常に学びがあるのでとてもよいのですが、それで社内に活動が閉じがちになってしまうのももったいないという気持ちがあります。今年はこれまでより (気楽に || 雑に) エントリなりコード片なりをアウトプットしたいと思います。

あとは pull request をもらってばかりなので、使っているライブラリなどに contribute できる余地があれば、できるだけしたいですね。