こんにちは。Podcastで自分の声を聞く度にガッカリしている照井@Sapporoです。(そんな残念ボイスを聞きたい方はこちら)
さて、今年のre:Inventも例年を超えるような大量の新サービスやアップデートの発表がありましたが、皆様いかがお過ごしでしょうか。思い思いに気になるサービスや新機能を試している頃合いかと思いますが、そんな中でAPI仕様やSDKの対応状況なんかが気になる場面もあるかと思います。
そんな時に見るドキュメントは何でしょうか。AWSのAPIを叩く時におそらくほとんどの方はSDKを使用するため、API仕様を確認する場合はおそらくはその時使っているプログラミング言語のSDKのドキュメントを見ることが多いかと思います。ですが、SDKのドキュメントは言語にも依るのですが、更新が遅れることがままあります。
今回は、そんな時にSDKの対応状況やインターフェース定義を確認する方法をご紹介したいと思います。対象はPythonとRubyです。
方法
GitHubのリポジトリを見る
「え、ソースコード読めって・・・?」って思ったアナタ、まあその通りではあるのですが、ちょっと違います。実はPythonとRubyのSDKは特殊な方法によってAPIを実装しているため、わりと簡単に確認ができるのです。
見る場所
- Ruby → https://github.com/aws/aws-sdk-ruby/tree/master/aws-sdk-core/apis
- Python → https://github.com/boto/botocore/tree/develop/botocore/data
この中に、各サービス毎のAPIが定義されたJSONが入っています。ここを見れば定義が確認でき、平易なJSONなので比較的に簡単に読めます。
見方
boto3(Python)のAPI Gatewayの定義を例に見てみましょう。
JSONの1階層目に operations というキーがあり、その中に以下のような各APIの定義があります。
{
"CreateAuthorizer":{
"name":"CreateAuthorizer",
"http":{
"method":"POST",
"requestUri":"/restapis/{restapi_id}/authorizers",
"responseCode":201
},
"input":{"shape":"CreateAuthorizerRequest"},
"output":{"shape":"Authorizer"},
"errors":[
{"shape":"BadRequestException"},
{"shape":"UnauthorizedException"},
{"shape":"NotFoundException"},
{"shape":"LimitExceededException"},
{"shape":"TooManyRequestsException"}
],
"documentation":"Adds a new Authorizer resource to an existing RestApi resource. "
}
}
ここで注目すべきはキーの名前と input と output です。他は errors がエラーハンドリングで場合によっては必要になるくらいで、あとは基本的にSDK自身がAPIコールを組み立てるためだけに使用するものであって、SDKを使用するユーザは意識しなくて良い情報です。
まず、キーの名前は言わずもがなかもしれませんが、メソッド名に対応します。
そして、input と output の両方に shape というキーが存在し、 CreateAuthorizerRequest や Authorizer という名前が入っています。これが呼び出す際の引数や返り値を定義するオブジェクトの名前になります。
では、 CreateAuthorizerRequest を同JSONから探してみましょう。 output にある Authorizer についても見方は同様です(ので、割愛します)
{
"CreateAuthorizerRequest":{
"type":"structure",
"required":[
"restApiId",
"name",
"type",
"identitySource"
],
"members":{
"restApiId":{
"shape":"String",
"documentation":"The RestApi identifier under which the Authorizer will be created.
"location":"uri",
"locationName":"restapi_id"
},
"name":{
"shape":"String",
"documentation":"<p>[Required] The name of the authorizer.</p>"
},
"type":{
"shape":"AuthorizerType",
"documentation":"<p>[Required] The type of the authorizer.</p>"
},
"providerARNs":{
"shape":"ListOfARNs",
"documentation":"<p>A list of the Cognito Your User Pool authorizer's provider ARNs.</p>"
},
"authType":{
"shape":"String",
"documentation":"<p>Optional customer-defined field, used in Swagger imports/exports. Has no functional impact.</p>"
},
"authorizerUri":{
"shape":"String",
"documentation":"<p>[Required] Specifies the authorizer's Uniform Resource Identifier (URI).</p>"
},
"authorizerCredentials":{
"shape":"String",
"documentation":"<p>Specifies the credentials required for the authorizer, if any.</p>"
},
"identitySource":{
"shape":"String",
"documentation":"<p>[Required] The source of the identity in an incoming request.</p>"
},
"identityValidationExpression":{
"shape":"String",
"documentation":"<p>A validation expression for the incoming identity.</p>"
},
"authorizerResultTtlInSeconds":{
"shape":"NullableInteger",
"documentation":"<p>The TTL of cached authorizer results.</p>"
}
},
"documentation":"<p>Request to add a new <a>Authorizer</a> to an existing <a>RestApi</a> resource.</p>"
}
}
ここまで来ればほぼ見たままでおわかりかもしれませんが、 members の中身が引数の情報です。キーが引数名に対応し、 shape が型に対応します(さらにオブジェクトとなっている場合もありますので、その場合は同じように見ていきます)。そして、その中で、指定が必須のものが required に列挙されます。
このように見ていけば、ドキュメントが追従する前に仕様を把握することが可能です。
余談とまとめ
公式のSDKに依らないAPIドキュメントを確認しても良いのですが、上記のやり方になれてしまったので最近は分かりませんがそれも遅れることがあるのと、サービスによって書き方がマチマチで、個人的な感覚ですが理解しづらいことがけっこう多いです。また、GitHubで見ると対応状況も履歴で分かるので良いというのもあります。
余談ですが、PythonとRubyのAWS SDKはこういった低レベルのAPI定義や認証などといった共通部分が実装されているcore部分と、ユーザが使用するSDK部分の実装が分離されています。あくまで体感ですが、両言語ともにこういった実装になってから最新サービスや機能のAPI対応が早く、ほぼ発表と同時に実装されるようになりました。
エディタの補完が効かないというような問題もあったりしますが、こういった画一的な方法を用いてメタプログラミング的な手法で実装を省略して更新を早めるやり方は非常に参考になりますね。
ただ触ってみて使い方を把握することはもちろん必要ですが、API仕様を把握してより便利に使える方法や足りない機能を補う方法を見出していくことが我々のようなAWSのプロフェッショナルには求められることだと思いますので、より精進していきたいものですね。