Monthly Archives: October 2013

HTTPヘッダにUNIX Timestampを入れるべきではないのか

APIを設計していてHTTPヘッダに情報を入れることがあるけれど、その際に時間を入れたい時があります。その際にどんな形式にすればいいのかなっていう話題です。

時間というのはいろいろな形式で表現が可能です。

形式名
RFC 1123 Thu, 17 Oct 2013 23:12:00 JST
ISO 8601 20131017T231200+0900
UNIX Timestamp 1381999405

で、この中で一番何がプログラム的に取り扱いやすいかといえばUNIX Timestamp、いわゆるエポック秒かなと自分は思っています。数値だし、それにタイムゾーンの概念がないので世界に単一のタイムゾーンしか無いと思っているエンジニアが変な値を入れる危険性も少ないと思われるから。しかも開発で使う言語はほぼすべてUNIX Timestampと自前の日時表現の変換の仕組みを提供しているし。他の形式だとフォーマットをこちらで指定しなくちゃいけなかったりして面倒な場合もあります。

で、APIには一人のユーザーからのアクセス数(あるいは1アプリケーションなど)を制限する「レートリミット」という仕組みを導入しているものが多くてその際にはX-RateLimit-Limit(あるいはX-Rate-Limit-Limit)をはじめとするヘッダを使うのがデファクトスタンダードっぽいです。

ヘッダ名 説明
X-Rate-Limit-Limit 単位時間あたりのアクセス上限
X-Rate-Limit-Remaining アクセスできる残り回数
X-Rate-Limit-Reset アクセス数がリセットされるタイミング

TwitterがAPI version 1.1で導入したのがはじめかな(調査中)と思うのですが、今は普通に使われています。例えばGitHubもちょっと名前は違いますがほぼ全く同じです。Foursquareもほぼ同じ。その他たくさんあります。こんなまとめもありました。

Rate-LimitとするかRateLimitとするかはどっちにするべきかよくわかりませんが、自分ならRate-Limitとするかなと思います。

そしてこの中にX-Rate-Limit-Reset(X-RateLimit-Reset)というヘッダがあって(Foursquareなどこれを返さないものもある)、これはAPIの利用制限が解除される時間を表しますが、UNIX Timestampで値が入ってるケースが多いのです。TwitterもGitHubもそうです。

でもこれに異議を唱えてる人がいて、Best Practices for Designing a Pragmatic RESTful APIという記事があり、その中でUNIX Timestampは使うな、解除までの秒数(デルタ秒)を使え!と強く主張していました。この記事を書いたVinay Sahniさんの主張では、HTTPでは使っていい日付形式はRFC1123で、UNIX Timestampは使えないんだから仕様に反してるんだよ!使うんだったらRFC1123形式を使うべきだ、と書かれています。

え、そうなのか、と改めてHTTP 1.1の仕様に立ち返ってみたところ、確かにHTTPでは時間を表すのに、以下の3つの形式か、デルタ秒を使わないといけないと書いてありました。

形式名
RFC 822, updated by RFC 1123 Sun, 06 Nov 1994 08:49:37 GMT
RFC 850, obsoleted by RFC 1036 Sunday, 06-Nov-94 08:49:37 GMT
ANSI C’s asctime() format Sun Nov 6 08:49:37 1994

定義で言うとrfc2616で以下のようになってます。

そしてたしかに例えばきちんと定義されているHTTPヘッダを見てみると、例えばRetry-Afterは以下のようになっています。

そうだったのか…ということでHTTPのヘッダにUNIX Timestampを使うのは厳密にはダメらしいんですけど、やっぱりUNIX Timestampはハンディだし使いたいなあと思っているこの頃です。

ちなみにHerokuも使っていますね。みんなこの辺を知っててあえてUNIX Timestampを選んだんでしょうか。

X-Request-Start: unix timestamp (milliseconds) when the request was received by the router

個人的にはUNIX Timestampを使い続けたいところ。例えばスマフォアプリのサーバクライアント連携とか、半ばプライベートなAPIの場合は使ってしまっていい気もしますが、一般公開するAPIの場合はどうすべきか悩むところです。デルタ秒だといつを基準としたデルタ秒だよ、という気もするし…まあDateヘッダで示された時間からですね。ただ、UNIX Timestampも随分利用されてきているので、仕様があとから追いついていく可能性はあるような気がします。

PNG画像のファイルサイズをなるべく小さくしたい

PNGやJPEGなんかのファイルはいろいろなメタ情報が含まれているのでそれを削除したり、カラーパレットや圧縮の最適化でサイズを小さくでき、そのための色々なツールが存在しています。ウェブサイトで公開するにも、モバイルアプリ内で使うにも、同じ画像ならファイルサイズが小さいに越したことはないので、そのへん色々調べました。今回はPNGについてです。

ウェブサービスだとKraken.ioとかTinyPNGとかがあります。ただこれらはウェブ上で使うものなので手作業が発生してちょっと面倒。せっかくならビルドプロセスに組み込んだりできたほうがいいので、ローカルで使えるツールのほうがいいです。Kraken.ioはAPI用意してくれていますが、月額$10で1000画像までとちょっとお高いです。

でMacでPNGの最適化を行えるツールをいろいろ試して何をするのが一番いいんだということを調査したのでこれはその結果とメモです。調査したツールは5種類。

以下のファイルを圧縮しました。これは自分のプロフィールアイコンとかに使ってる奴とほぼ同じもので、SPSTUDIOっていうサイトで作成したものです。

zopflipng fs8 re PNG画像のファイルサイズをなるべく小さくしたい

結果は以下のとおり

ツール名 コマンド サイズ 比率
PNGOUT pngout src.png -c2 -f3 dst.png 33,684 0%
AdvanceCOMP advpng -z -4 src.png 25,731 76.4%
OptiPNG optipng -o7 -strip all src.png 27,835 82.6%
Pngcrush pngcrush -brute src.png dst.png 27,528 81.7%
zopflipng zopflipng src.png dst.png 25,707 76.3%

 

最後のzopflipngはGoogleが2013年3月に公開したzopfliという新しいDeflate互換の圧縮アルゴリズムを使うもので、zopfliと一緒のリポジトリに入っているが、1.0.0のパッケージには入ってないのでリポジトリから直接持ってこないといけません。

結果を見ると、AdvanceCOMPzopflipngが圧倒的に圧縮率が高いです。この画像だとzopflipngに軍配が上がってますけど、他に試したものではAdvanceCOMPが勝ったりもする。おお、と思って調べたら、AdvanceCOMPは今年の3月にzopfliを使えるようにアップデートがなされていた(2005年以来のアップデート)のでした。それ以前にインストールしている人はすぐにアップデートした方がいいです。

今回の画像は24bitのPNGファイルですが、インデックスカラーにしたほうがサイズは減少するはずなので、pngquantというツールでインデックスカラー化しました。不可逆な圧縮ですが、今回の場合は見た目には変化はほぼわかりません。

ちなみにpngquantは最近2.0が公開され、アルゴリズムが見直されてクオリティが上がりました。サイト上にも「Ver.1はもう使わないように」って書いてあります。で、両方で圧縮してみたところ、やや差がでました。もしまだ1.xを使っているようならアップグレードしたほうが良さげです。

バージョン サイズ 比率
1.8.3 14,840 44.1%
2.0.1 14,450 42.9%

 

その後、pngrewriteというファイルで更にパレットを最適化しました。このツールの更新は2010年で止まっているのですが、とりあえず使ってみたところ、パレット数が256から253に減って25バイトだけ減りました。

状態 サイズ 比率
pngrewrite前 14,450 42.9%
pngrewrite前 14,425 42.9%

 

まあpngquantでカラーパレット最適化してるからあたり前なんだろうけど、じゃあなんで3個減らせたのか?とかまだ調べる余地はいろいろありそう。とりあえず先に進みます。

ツール名 コマンド サイズ 比率
PNGOUT pngout src.png -c2 -f3 dst.png 14,425 0%
AdvanceCOMP advpng -z -4 src.png 13,169 91.2%
OptiPNG optipng -o7 -strip all src.png 14,396 99.8%
Pngcrush pngcrush -brute src.png dst.png 14,394 99.8%
zopflipng zopflipng src.png dst.png 13,156 91.2%

 

今度も若干zopflipngに軍配があがったです。ちなみにzopflipngが出力した結果はこちら。

zopflipng fs8 re PNG画像のファイルサイズをなるべく小さくしたい

画像によっておそらくツールごとの差異は違ってくると思うのですが、とりあえずAdvanceCOMPとzopflipngのどちらかを使うのが良さげですね。

ちなみにGUIでやるなら今回調べたツールはすべてImageOptimに統合されているみたいです。こちらためしてみると、24bitの場合はいまいちだったのですが、インデックスカラーの場合はzopflipngに迫るサイズになりました。

状態 サイズ 比率
24bit 26,062 42.9%
インデックスカラー 13,157 42.9%

 

あと最初に言及した、ウェブサービスとして公開されているツールを2つ調べました。

ツール名 サイズ 比率
オリジナルファイル 33,684 0%
Kraken.io LossLess 25,734 76.4%
Kraken.io Lossy 13,221 39.2%
TinyPNG 14,571 43.3%

 

TinyPNGはインデックスカラー化しかできませんが、KrakenはLossLessとLossyが選べるので両方を比較しました。けど今回の場合はどちらもコマンドラインツールのコンボにかなわなかった感じなので、AdvanceCOMPかzopflipng手元で処理してしまってもよい感じです。