GitHubプラットフォームとの統合に興味はありますか。 同じことを思っている仲間がいますよ。 このガイドは、ユーザに最高のエクスペリエンスを提供し、かつAPIと確実にやり取りするアプリを構築するために役立ちます。
GitHubから配信されるペイロードの機密を確保する
GitHubから送信されたペイロードの機密を確保することは非常に重要です。 ペイロードでパスワードなどの個人情報が送信されることはないものの、いかなる情報であれ漏洩することは好ましくありません。 コミッターのメールアドレスやプライベートリポジトリの名前などは、機密性が求められる場合があります。
いくつかのステップを踏むことで、GitHubから配信されるペイロードを安全に受信できます。
- 受信サーバーは必ずHTTPS接続にしてください。 By default, GitHub will verify SSL certificates when delivering payloads.
- ペイロードがGitHubから配信されていることを確実に保証するため、シークレットトークンを提供します。 シークレットトークンを強制することにより、サーバーが受信するあらゆるデータが確実にGitHubから来ていることを保証できます。 サービスのユーザごとに異なるシークレットトークンを提供するのが理想的です。 そうすれば、1つのトークンが侵害されても、他のユーザは影響を受けません。
同期作業より非同期作業を優先する
GitHub expects that integrations respond within 30 seconds of receiving the webhook payload. サービスの応答時間がそれ以上になると、GitHubは接続を中止し、ペイロードは失われます。
サービスの完了時間を予測することは不可能なので、「実際の作業」のすべてはバックグラウンドジョブで実行すべきです。 バックグラウンドジョブのキューや処理を扱えるライブラリには、Resque (Ruby用)、RQ (Python用)、RabbitMQなどがあります。
Note that even with a background job running, GitHub still expects your server to respond within thirty seconds. サーバは何らかの応答を送信することにより、ペイロードの受信を確認する必要があります。 サービスがペイロードについての確認を可能な限り速やかに行うことは非常に重要です。そうすることにより、サーバがリクエストを継続するかどうか正確に報告できます。
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
エラーが発生します。
繰り返し発生する検証エラーを意図的に無視すると、不正利用によりアプリケーションが停止されることがあります。