GitHubプラットフォー� との統合に興味はありますか。 同じことを思っている仲間がいますよ。 このガイドは、ユーザに最高のエクスペリエンスを提供し、かつAPIと確実にやり取りするアプリを構築するために役立ちます。
GitHubから配信されるペイロードの機密を確保する
GitHubから送信されたペイロードの機密を確保することは非常に重要です。 ペイロードでパスワードなどの個人情� �が送信されることはないものの、いかなる情� �であれ漏洩することは好ましくありません。 コミッターのメールアドレスやプライベートリポジトリの名前などは、機密性が求められる� �合があります。
いくつかのステップを踏むことで、GitHubから配信されるペイロードを安全に受信できます。
- 受信サーバーは必ずHTTPS接続にしてく� さい。 デフォルトでは、GitHubはペイロードを配信する際にSSL証明書を検証します。
- ペイロードがGitHubから配信されていることを確実に保証するため、シークレットトークンを提供します。 シークレットトークンを強制することにより、サーバーが受信するあらゆるデータが確実にGitHubから来ていることを保証できます。 サービスのユーザごとに異なるシークレットトークンを提供するのが理想的です。 そうすれば、1つのトークンが侵害されても、他のユーザは影響を受けません。
同期作業より非同期作業を優先する
GitHubは、webhookペイロードを受信後30秒以内にインテグレーションが応答することを求めています。 サービスの応答時間がそれ以上になると、GitHubは接続を中止し、ペイロードは失われます。
サービスの完了時間を予測することは不可能なので、「実際の作業」のすべてはバックグラウンドジョブで実行すべきです。 バックグラウンドジョブのキューや処理を扱えるライブラリには、Resque (Ruby用)、RQ (Python用)、RabbitMQなどがあります。
バックグラウンドジョブが実行中でも、GitHubはサーバが30秒以内で応答することを求めていることに注意してく� さい。 サーバは何らかの応答を送信することにより、ペイロードの受信を確認する必要があります。 サービスがペイロードについての確認を可能な限り速やかに行うことは非常に重要です。そうすることにより、サーバがリクエストを継続するかどうか正確に� �告できます。
GitHubへの応答時に適切なHTTPステータスコードを使用する
各webhookには、デプロイメントが成功したかどうかを列挙する独自の「最近のデリバリ」セクションがあります。
ユーザへの通知には、適切なHTTPステータスコードを使用するべきです。 (デフォルトでないブランチから配信されたペイロードなど) 処理できないペイロードの受信を知らせるため、201
や202
といったコードを使用できます。 500
のエラーコードは、致命的な障害に用いましょう。
ユーザにできる� け多くの情� �を提供する
ユーザはGitHubに返信したサーバーの応答を調べることができます。 メッセージは明確で参考になるものとしてく� さい。
APIが送信するあらゆるAPIに従う
GitHubは、リダイレクトのステータスコードを提供することにより、リソースがいつ移動したかを明示します。 このリダイレクトに従ってく� さい。 すべてのリダイレクト応答は、Location
ヘッダに、移動する新しいURIを設定します。 リダイレクトを受け取ったら、削除する可能性がある非推奨のパスをリクエストしている� �合、新しいURIにしたがってコードを更新するようお勧めします。
アプリケーションをリダイレクトに従うよう設計する際に気をつけるべきHTTPステータスコードのリストをご用意しています。
手動でURLをパースしない
APIレスポンスには、URLの形でデータが含まれていることがよくあります。 たとえば、リポジトリをリクエストするときは、リポジトリをクローンするために使用できるURLの付いたclone_url
というキーを送信します。
アプリケーションの安定性を保つため、このデータをパースしようとしたり、先のURLの形式を予想して作成しようとしたりしないでく� さい。 URLを変更した� �合、アプリケーションが壊れるおそれがあります。
たとえば、ページネーションされた結果を扱う際は、末尾に?page=<number>
を付けてURLを構築したいと思うことがあります。 この誘惑に� けてはなりません。 ページネーションに関するガイドには、ページネーションされた結果を安全に扱うための信� �できるヒントがいくつか掲載されています。
イベントの処理前にイベントのタイプとアクションを確認する
webhookのイベントタイプは複数あり、各イベントは複数のアクションを持つことができます。 GitHubの機能セットが増えるにつれて、新しいイベントタイプを追� したり、既存のイベントタイプに新しいアクションを追� したりすることがあります。 Webhookの処理を行う前に、イベントのタイプとアクションをアプリケーションが明示的に確認するようにしてく� さい。 X-GitHub-Event
リクエストヘッダは、受信したイベントの種類を知り、それを適切に処理するために利用できます。 同様に、ペイロードにはトップレベルのaction
キーがあり、関連オブジェクトに対して実行されたアクションを知るために利用できます。
たとえば、GitHubのwebhookを [Send me everything] に設定している� �合、新しいイベントのタイプやアクションが追� されると、アプリケーションはそれらの受信を開始します。 ですから、あらゆる類のcatch-all else構文は使用をお勧めしません。 たとえば、次のコード例をご覧く� さい。
# Recommended: explicitly check each event type
def receive
event_type = request.headers["X-GitHub-Event"]
payload = JSON.parse(request.body)
case event_type
when "repository"
process_repository(payload)
when "issues"
process_issue(payload)
when "pull_request"
process_pull_requests(payload)
else
puts "Oooh, something new from GitHub: #{event_type}"
end
end
このコード例では、repository
またはissues
イベントを受信すると、process_repository
およびprocess_issues
メソッドが正しく呼び出されます。 しかし、他のイベントタイプでは、process_pull_requests
が呼び出されることになります。 新しいイベントタイプが追� されると、誤った動作を引き起こすことになり、新たなイベントタイプはpull_request
イベントと同じ方法で処理されることになるでしょう。
代わりに、イベントのタイプを明示的に確認し、それに応じて処理するようお勧めします。 次のコード例では、pull_request
イベントを明示的に確認し、else
節は新しいイベントタイプを受信したことを単に記録しています。
# Recommended: explicitly check each event type
def receive
event_type = request.headers["X-GitHub-Event"]
payload = JSON.parse(request.body)
case event_type
when "repository"
process_repository(payload)
when "issues"
process_issue(payload)
when "pull_request"
process_pull_requests(payload)
else
puts "Oooh, something new from GitHub: #{event_type}"
end
end
各イベントも複数のアクションを持つことができるため、アクションも同様に確認することをお勧めします。 たとえば、IssuesEvent
ではいくつかのアクションが可能です。 例としては、Issueが作成されたときのopened
、Issueがクローズしたときのclosed
、Issueが誰かに割り当てられたときのassigned
が挙げられます。
イベントタイプを追� するのと同じように、既存のイベントに新しいアクションを追� できます。 ですから、イベントのアクションを確認する� �合も>あらゆる類のcatch-all else構文は使用をお勧めしません。 代わりに、イベントタイプの例と同様、イベントのアクションも明示的に確認するようお勧めします。 この例は、上記のイベントタイプで示したものと非常に似通ったものです。
# Recommended: explicitly check each action
def process_issue(payload)
case payload["action"]
when "opened"
process_issue_opened(payload)
when "assigned"
process_issue_assigned(payload)
when "closed"
process_issue_closed(payload)
else
puts "Oooh, something new from GitHub: #{payload["action"]}"
end
end
この例では、始めにclosed
アクションを確認してから、process_closed
メソッドを呼びます。 未確認のアクションは、今後の参考のために記録されます。
APIエラーの扱い
あなたのコードが決してバグを発生させなかったとしても、APIにアクセスしようとするとき立て続けにエラーが発生することがるかもしれません。
繰り返し表示される4xx
や 5xx
のステータスコードを無視せずに、APIと正しくやり取りしていることを確認してく� さい。 たとえば、エンドポイントが文字列を要求しているのに数値を渡している� �合、5xx
検証エラーが発生し、呼び出しは成功しません。 同様に、許可されていないエンドポイントまたはは存在しないエンドポイントにアクセスしようとすると、4xx
エラーが発生します。
繰り返し発生する検証エラーを意図的に無視すると、不正利用によりアプリケーションが停止されることがあります。