Azure Functions で REST っぽい WebAPI を作りたいです。
REST な API については、
にある通りで。
例えば、日本の住所を REST な API で考えると、
GET https://hoge.com/api/address/23 <-- 愛知県のデータを取得
GET https://hoge.com/api/address/23/106 <-- 愛知県/名古屋市中区のデータを取得
POST https://hoge.com/api/address/23/112 <-- 愛知県/名古屋市南区のデータを追加
PUT https://hoge.com/api/address/23/113 <-- 愛知県/名古屋市守山区のデータを更新
DELETE https://hoge.com/api/address/13 <-- 東京都のデータを削除
という感じになります。あ、説明不足でごめん 23
は総務省が定めた 都道府県コード 、112
は 市区町村コード (の下3桁)です。
このような API を Azure Functions で作りたいと思っても、通常の Http Trigger では「動的な」「多段の」パスは定義できません。
そんなときに使えるのが Azure Functions のプロキシ(関数プロキシ)機能です。
関数プロキシは Http Trigger な Function の前に配置され、URL やクエリ文字列、リクエストメソッドやレスポンスのカスタマイズを可能にします。ちょうど AWS の API Gateway に相当する機能だと考えられます。
Azure Functions でも、こんな機能を使って束ねることができます。https://t.co/GrXX7yLo6K previewだと思うけど。
— Takekazu Omi (@takekazuomi) 2018年7月26日
実際に REST API っぽい使い勝手を、プロキシを使って実現してみます。
ドンッ!!
Functions Apps にプロキシというグループがあるので、そこに新しいプロキシを作ります。名前 "Proxy01" は任意の名称で、これは外部に公開される URL には影響を与えません。
ルートテンプレートで、 {table}
や {*path}
と付けているのが変数で、名称は任意です。
{table}/{*path}
と定義すると、呼び出した URL のパス要素が、その変数に格納されます。
例えば次のようになります。
https://hoge.com/rest/address/23 ---> table='address', path='23'
https://hoge.com/rest/address/23/201 ---> table='address', path='23/201'
という感じで変数にURLパスが格納されます。定義で *path
とすると、「そこまでのパス文字列すべて」が格納されます(23/201
のように)。
そしてこの変数を別な場所で使用できます。ここでは 要求のオーバーライド の項目で、クエリパラメータとして利用します。
例えば、 table : {table}
という定義は、ルートテンプレートで定義した {table} 変数をクエリパラメータの table
にマッピングする、という意味です。
{request.method}
は組み込みの変数で、URL呼び出しのリクエストメソッド(GET/POST/PUTなど)を示します。
そして、このプロキシの透過先、実際の呼び出し先が バックエンドURL で指定されたURLで、通常は別な Http Trigger Function になると思います(このUIだけ見ると、Azure Functionsに限らず任意のURLを指定できるようですが)。
つまり、
https://hoge.com/rest/address/23/201
という URL が、別な URL
https://huga.com/MyHttpTrigger?table=address&path=23/201
に変換できたとみなせます。
あとは、バックエンドURLの方でクエリ文字列をよしなに処理すれば、REST っぽい API が実装できそうです。
(https://hoge.com/api/address/23/112
のようなリストの中の要素をダイレクトに示すURLは、 path に 23/112
が入るだけなので、この文字列を自力でパースする必要はあります。)
Azure Functions の Http Trigger では次のようにクエリ文字列から table
, method
, path
を取り出せるので、あとは SQL を組み立てるなり、DAO(Data Access Object) にお任せするなりできます。
MyHttpTrigger の index.js
module.exports = function (context, req) {
const table = req.query.table || '';
const method = req.query.method || '';
const path = req.query.path || '';
context.res = {
headers: {
'Content-Type': 'application/json'
},
body: `table=${table}, method=${method}, path=${path}`
};
context.done();
};