パルカワ2

最近はFlutterをやっています

Web APIを作るときに考えること。

この記事はPepabo Advent Calendar 2014の11日目の記事です。
前日は、tnmtさんのVagrantのshell provisionerでApacheのビルド済tarボールをOSバージョン毎に作る術でした。

はじめに

今回は、Web APIを作るときに考えることをまとめました。
本当は、社内向けに資料を作っていて、社内の勉強会とかで話せればいいか〜って考えていたんですが、アドベントカレンダーのネタが本当になくて困っていたのでこれを使います。

対象者

APIを作る時、と書いてますが、クライアント側の人にとっても知っておく必要があることなので、サーバ側の人・クライアント側の人両方が対象者です。

APIを作るときに考えること

APIを作るとき」と言っても、色んな状況があります。
まずはそれを絞ります。

APIの種類

  • プライベートAPI
    • アプリのAPIなど使う人が限定されているもの
  • パブリックAPI

大きく分けるとこの2つがあります。
今回は「スマホアプリ用のプライベートAPI」について話します。
なので、パブリックAPIではやらないことを書きます。

作る時

  • まだAPIを運用していない時
  • 既にAPIを運用している時

APIを作る時は、この2つがあります。
今回は「まだAPIを運用していない時」について話します。
なので、運用している時点で必要性に気づいて開発するのでは遅く困ったことになりがちな事を書きます。

正式なタイトルは「まだ運用していないスマホアプリ用プライベートAPIを開発する時に考えること」

長い。ウケる。もっとシュッとしろ

1. 強制アップデートを考える

「アプリを強制アップデート」というととても良くないことで、やりたくないかもしれませんが、それが出来るようにしておくのはとても大事なことです。

強制アップデートとは

強制アップデートとは、アプリをアップデートしないと使えないようにすることです。それと共に「アプリを利用するにはアップデートが必要です」とユーザーに促すことです。

なぜやるか

特定のアプリのバージョンで起きるバグがとても致命的なものだった場合、そのバージョンを使ってほしくないということが起きます。
そういった場合、アップデートを必須にするという時があります。

もちろん、そういうことを起こさないようにするのは当たり前ですが、人間なので間違いは起きます。その間違いが起きた時にどう対処するかが重要で、もしもの時のために強制アップデート出来るようにしておくのは悪いことではないです。

またバグ以外でも、ずっと前に出したアプリをサポートし続けるのは非常に大変です。
iOS6以上サポート以上をサポートしています」はあると思うんですが、それと共に「アプリのバージョンn以上に対応しています」も考えるべきです。

どうやるか

APIにバージョンを送って、その特定のバージョン以下ならリクエストを拒否して、アプリにアップデートを促すレスポンスを返す方法があります。
またアプリ起動時、最初に必ずアクセスするJSONを決めておき、そこにクライアントの必要最低バージョンを記述することも出来ます。

注意事項
  • 強制アップデートは、やりすぎるとユーザーは不快に感じる

2. 通信失敗を考える

なぜやるか

スマホアプリは、当然スマホで使われます。スマホは携帯端末なので、様々な人が様々な場所で使います。
なので「地下に入った」「トンネルに入った」など、通信中に電波状況が悪くなり通信失敗することがあります。
データを取得するときに、リトライすることになるのは大きな問題ではないです。
ただ、データを更新するときになってしまうと少々やっかいです。

f:id:hisaichi5518:20141211124249p:plain

この図のように、サーバ側では処理が終了していて、レスポンスを返したのに、クライアントが正常にレスポンスを受け取れなかった場合、何も考えず100円を払う処理をリトライしてしまうと二度処理を行ってしまいます。つまり「Aを買おうとしたらお金が2倍取られた」というお問い合わせがくる可能性があるということです。実際はAが2つ買われてしまってお金が減ってしまったということです。

どうやるか

一つ一つのリクエストにidを振り分け、APIに送信します。API側は、短時間(10分程度)レスポンスをキャッシュして、同じリクエストIDでリクエストがきたらキャッシュしているレスポンスを返します。
クライアントは、リトライするときは失敗したリクエストと同じリクエストIDを使用するようにする必要があります。

注意事項
  • これはGETのときは必要なく、POSTの時に必要なので、そのように実装しておくと無駄にキャッシュが膨らまない。

3. メンテを考える

緊急メンテ、予定されたメンテ。どちらもやりたくないですが、ユーザーに今起きている事を伝える方法を持っておくべきです。

なぜやるのか

例えば、緊急メンテが行われている時、クライアントにメンテが行われていることを知る方法がなければ、ユーザーが何が起こっているのかわかりません。ユーザーに今起きていること、どのくらいかかるか等ちゃんとアプリで説明する必要があります。

どうやるのか

アプリ起動時、必ずアクセスするJSONを決めて、メンテナンス情報を返すようにします。

{
  "maintenance" : {
    "start": "2014-01-01 00:00:00",
    "end": "2014-01-01 18:00:00",
    "message": "メンテなう 18時に終わりそう"
  }
}

まとめ

今回は3つだけ考えることを書きました。しかし残念なことにAPIを作る時には、まだまだたくさん考える必要があります。例えば、レスポンスをどう返すか?エラーをどう返すか?エラーの何を返すか?などなど...。

APIに限らず、なにかを作る時は考える事、決める事が多いので、会社・チームで、色々と違うことがあると思います。そういった知見をどんどん公開して、シュッと面白いサービス・便利なサービスを出せていけたら良いなあ、と思います。またそういったことがしたい人間と僕は一緒に働きたいです。
http://pepabo.com/recruit/career/#jobs

明日

明日は、弊社技術責任者のあんちぽくんさんです。どんな記事を書いてくれるんでしょうか。楽しみですね!!!

謝辞

この記事はもともとは acidlemonさんが作った非公開の資料があり、許可をもらってからそれを見た記憶と実装した経験を頼りに書きました。記憶も曖昧で、かつゲームに特化したものは何個か飛ばしてますが、acidlemonさんありがとうございます。有益資料公開待ってます。

読みましょう。

Web API: The Good Parts

Web API: The Good Parts

Data::DumperとB::Deparseを合わせて使ってみる。

この記事は、 Perl Advent Calendar 2014の11日目の記事です。
前日は、mihyaeru21さんのPerlでベンチマークでした。

B::Deparseの紹介

B::DeparseというのがPerlにあります。
ゴチャゴチャしたコードをいい感じにして見たいよ〜って時便利です。

use strict;
use warnings;

print +('`'^'(').('`'|'%').('`'|',').('`'|',').('`'|'/').' '.('['^',').('`'|'/').('['^')').('`'|',').('`'|'$').'!';

こういうコードがあったとします。それをperl -MO=Deparse ...で実行するだけです。

$ perl -MO=Deparse test.pl
use warnings;
use strict;
print 'Hello world!';
test.pl syntax OK

なにこれすごい!!!!!!!!!!!!

Data::Dumperと使う

でもまあ、こんな意味不明なコードを仕事で見ることがない。これで終わるのも忍びない。どうしたもんかねーとPerl Advent Calendar 2014眺めてたら、パピックスが良い記事を書いてた。

DDPでdeparseを使う例がある。Data::Dumperはないじゃん!これだ!
通常、Data::Dumperにsubを渡すとこうなる。

use strict;
use warnings;
use Data::Dumper;

my $code = sub {
    print "Hello, World";
};

print Dumper $code;
__END__
$VAR1 = sub { "DUMMY" };

DUMMY!!!!!!!!!!!!!!!!!!わかりにくい!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
というわけで見るぞ!!!!!!!

use strict;
use warnings;
use Data::Dumper;

$Data::Dumper::Deparse = 1; # 追加だ!

my $code = sub {
    print "Hello, World";
};

print Dumper $code;
__END__
$VAR1 = sub {
            use warnings;
            use strict;
            print 'Hello, World';
        };

見れた!!!!!!!!!!!!!シュッ!!!!!!!!!!!!!!!!!!!!!としている!!!!!!!!!!!!!!!!!

まとめ

Data::DumperもB::Deparseを合わせて使える。

明日

明日は、zoncoenさんです。楽しみですね!