Webアプリ初心者が、いきなりWeb APIを作成する場合は?
覚えること
こういったことを心がけると、比較的早くマスターできます。
- データの取得は主にGETかPOSTパラメータだが、その違いを覚える
- 最初はGETで、SELECTから
- Webシステムでダンプコマンドがある場合は、どのようなパラメータが渡ってきているか?を見てみる
- パラメータをもとにSQLを発行するが、その結果をダンプできるとなお良い
- OKなら、それを構造体⇒JSON化してみる
- POSTは入力フォームを作って、そこから実行してみる
もし、社内に先人がいない場合は、荒野の一人旅になると思いますが、まず、予定されるWeb言語にこのような機能があるかを調査しましょう。
JSONからその言語で利用できる変数体系に変換、あるいはJSONに変換できないと意味がありません。
あなたはJSONのフォーマットに関する知識はゼロなのですから、JSON変換プログラムを一から作らないといけないような言語は、絶対に避けましょう。
AS400のケース
私の周りにはAS400の技術者が多いのですが、AS400のデータをAPIとして活用したいというニーズはあります。
AS400はJSON変換ができないので、中間サーバーを作り、そこでJRuby+JDBCなりでアクセスして、JSONはそっちで作成することをおすすめいたします。
(AS400はデータサーバーに特化します。)
さらに、AS400はActiveRecordを想定したファイルレイアウトではないため、JRubyベースで、SQL直接発行+SinatraでAPI化…といった感じでしょうか。
AS400内に中間サーバーを作成する方法もあるとは思いますが、果たして、その技術者が確保できるかどうか?
Linux技術者が多いのでしたら、中間サーバーは外出ししたほうが楽かもしれません。
GET/POSTの違い
GET/POSTとは何でしょうか?
大雑把に以下の違いで覚えると楽です。
GET
詳細ページなどのリンクをクリックした際、ブラウザのURL欄の後ろに「?」から始まる文字列がありませんか?
それがGETパラメータです。
「?aaa=bbb&ccc=ddd」ですと…<
- aaaというパラメータにbbbという値を送る
- cccというパラメータにdddという値を送る
となります。
なんちゃってRESTful APIのGET型では、主に、以下の処理で利用されます。
- 照会画面(SELECT文)
- レコードの削除や取り消し(DELETE文やUPDATE文)
- トグルスイッチの切替(UPDATE文)
以降はSELECTでの処理例です。
- GETパラメータをもとにSQL文を組み立てる。
- SQL文(SELECT文を実行する)
- 取得したデータを構造体(言語によってはハッシュ・連想配列)や配列に展開する
- 構造体(あるいはハッシュ・連想配列)をJSONに変換したものを、HTMLの代わりに返す
(text/htmlではなくapplication/jsonで返す)
といった手順になります。
DELETEやUPDATEについては、
- GETパラメータをもとにSQL文を組み立てる。
- SQL文(DELETEまたはUPDATE文を実行する)
- 成功あるいは失敗を構造体にセットする
(失敗した場合はメッセージも返す事が多い) - 構造体(あるいはハッシュ・連想配列)をJSONに変換したものを、HTMLの代わりに返す
(text/htmlではなくapplication/jsonで返す)
といった手順になります。
昔はXMLというものを返していましたようですが、廃れてきていますね。
JSONのほうがわかりやすいので、そちらで統一しましょう。
POST
登録・変更画面の入力フォームのソースを覗くと、
<form ~ method="POST"> <input type="~" name="hoge" value="初期値"> </form>
となっていませんか?
上記の例ですと、ボタンをクリックした後の次のページでは、以下の値が取得できます。
- hogeというパラメータに「初期値」という値
(フォームに入力された場合は、入力値に差し替えられる)
登録・変更画面のに使用されるPOSTの場合は、GETとは異なり「?~」で受け渡しをせず、表に見えない形で、次のページに受け渡しを行います。
たまに、入力フォームかつmethod属性がGETの場合もありますが、その場合は「?~」で渡された場合と同様になります。
ただし、文字列長に制限があったり、エンコード・デコードのわずらわしさから、登録画面はほぼPOSTだと思います。
登録・変更画面のに使用されるPOSTの場合は、GETとは処理手順が多少異なります。
- 入力パラメータについての簡単なエラーチェックを行う
- 日付チェックや数値チェック、桁数チェック程度
- (DBのカラムの型や長さに沿ったチェックを行う)
- API送信元のシステムが、エラーチェックを満足に行えない場合
- 不足しているエラーチェックを行う
- エラーがあった場合は、
- 更新できない旨や、エラーメッセージをJSON化して返す
- NSERTまたはUPDATE文を発行する
- 成功あるいは失敗を構造体にセットする
(失敗した場合はメッセージも返す事が多い) - 構造体(あるいはハッシュ・連想配列)をJSONに変換したものを、HTMLの代わりに返す
(text/htmlではなくapplication/jsonで返す)
オフィスコンピュータの入力画面に近いですね。
多くの場合、入力先のシステムにてエラーチェックを行うのですが、サーバーサイド側の方でないと、より詳細なエラーチェックを行いケースがあります。
その場合は、エラーチェックを行い、エラーだった場合は、更新を行わずに、エラーメッセージを返します。
POSTの場合はフォームデータで統一させる
まれに、POSTで、フォームデータではなくJSONで欲しいというリクエストがありますが、そうすると、添付ファイルが渡せないので、私はフォームデータで統一しています。
Web言語によっては、クライアント側で「multipart/form-data」と明示しないと、API側が落ちる場合もありますので、注意しましょう。
submitで画面遷移させない
APIはJavascript側から実行されることも多々あり、その場合はsubmitではなく、Javascript側で戻り値を受け取り、処理を実行させます。
ただし、APIのみのテストであれば、POSTの場合は仮のフォームを作成しsubmitさせたり、GETの場合はURLを組み立てて直接実行させることが多いです。
JSONとは
JSONの定義
JSONとは、ざっくり説明すると、Javascriptの構造体から発展した書式です(ほぼ業界標準)。
定義不要で、見た目がシンプルなことから、Web APIではXMLではなくJSONを使うことが主流になっています。
構造体はAS400でいうとDS、Rubyでいうとハッシュ(に近いもの)かなと。
構造体の中に配列を入れたり、さらにその配列の中に構造体を入れたりできます。
JSONで使用する記号等
- {~} は構造体を表します
- [~] は配列を表します
- , 項目をつなぎます
- “~” 文字列の場合に囲みます
- {“key” : “value”}といった形で受け渡しします
(keyの箇所はJSONキーともいいます。構造体(連想配列)のキーになります。) - “arrayname” : で配列名となります
値にはNULLやtrue/falseも使えますが、言語によってはサポートしない、あるいは別値に変わってしまうものもあります。
その場合は…といいますか、最初からこれで統一してもらっています。
- NULLは””あるいは0に、あるいはデータが有る無いのフラグを渡す
- そのNULLが配列の場合はで
- ture/falaseは1/0で
といった代替値で受け渡すように依頼することが多いです。
SONの具体例(SELECT、一覧タイプ)
https://~/get_foo?bar=1
を実行したとして、その実行結果が複数レコード存在する場合は…
{ "error" : 0, "message" : [], "record" : [ {"id" : 10, "code" : "abc", "name" : "あいうえお", "price" : 123}, {"id" : 25, "code" : "def", "name" : "かきくけこ", "price" : 456} ], "record_count" : 2 }
となります。
これは…
- エラーもなく、SELECTは成功しましたよ
- 「bar=1」の条件に一致した、fooのレコード件数は2件ですよ
- レコード毎にcodeとnameとpriceをお渡ししますよ
を意味します。
そのSQLは、
SELECT id, code, name, price FROM foo WHERE bar='1'
といった感じでしょうか。
エラーの場合は…
{ "error" : 1, "message" : ["barの値が正しくありません。"], "record" : [], "record_count" : 0 }
レコード0件の場合は…
{ "error" : 0, "message" : [], "record" : [], "record_count" : 0 }
となります。
(ちょっと寂しい気もしますが…)<
JSONの具体例(SELECT、単票タイプ)
https://~/get_foo?id=10
のように、その実行結果が必ず1件の場合は、配列にせずに、
{ "error" : 0, "message" : [], "id" : 10, "code" : "abc", "name" : "あいうえお", "price" : 123 }
と、クライアント側から要求されることがあります。
ただ、レコードが取得できなかった場合、
{ "error" : 0, "message" : [], }
で渡した場合、クライアント側が、変数未定義で落ちてしまう可能性が高いです。
接続テストあるあるですね。
それでは、変数未定義を回避するために、文字列の場合は空、数値は0とした場合、
{ "error" : 0, "message" : [], "id" : 0, "code" : "", "name" : "", "price" : 0 }
idが0というレコードがあるのか無いのかが、後に不具合に発展するケースもありますので、一覧と同様、
{ "error" : 0, "message" : [], "record" : [ {"id" : 10, "code" : "abc", "name" : "あいうえお", "price" : 123} ], "record_count" : 1 }
一覧型のJOSNにするか、あるいは、
{ "error" : 0, "message" : [], "record_count" : 0, "id" : 0, "code" : "", "name" : "", "price" : 0 }
単票スタイルのままrecord_count
を設け、0の場合はデータなし、1の場合は1件取得できた…と判断したほうが、双方にとって幸せかもしれません。
JSONの具体例(SELECT以外)
エラーの場合は…
{ "error" : 1, "warning" : 0, "message" : ["名称は80文字以内にしてください。","単価は1円以上の値を入力してください。"] }
正常にINSERT(またはUPDATE)した場合は…
{ "error" : 0, "warning" : 0, "message" : [] }
随分と味気ない感じではありますね。
warningは、更新はしたが、ちょっと問題があるかもしれない場合を想定したものですが、そういったものがなければ、除去して構いません。
最後に
SELECTを中心にJSONの出力例を解説しましたが、そこまで難しくはありません。
がんばってくださいね。
さらに、実践的な記事も用意しています。
それでは、また。