ドキュメントには頻繁に更新が加えられ、その都度公開されています。本ページの翻訳はまだ未完成な部分があることをご了承ください。最新の情報については、英語のドキュメンテーションをご参照ください。本ページの翻訳に問題がある場合はこちらまでご連絡ください。

このバージョンの GitHub Enterprise はこの日付をもって終了となりました: 2021-03-02. 重大なセキュリティの問題に対してであっても、パッチリリースは作成されません。 パフォーマンスの向上、セキュリティの改善、新機能のためには、最新バージョンのGitHub Enterpriseにアップグレードしてください。 アップグレードに関する支援については、GitHub Enterprise supportに連絡してください。

インテグレーターのためのベストプラクティス

GitHub APIと確実にやり取りできるアプリケーションを構築し、ユーザに最高のエクスペリエンスを提供しましょう。

ここには以下の内容があります:

GitHubプラットフォームとの統合に興味はありますか。 同じことを思っている仲間がいますよ。 このガイドは、ユーザに最高のエクスペリエンスを提供し、かつAPIと確実にやり取りするアプリを構築するために役立ちます。

GitHubから配信されるペイロードの機密を確保する

GitHubから送信されたペイロードの機密を確保することは非常に重要です。 ペイロードでパスワードなどの個人情報が送信されることはないものの、いかなる情報であれ漏洩することは好ましくありません。 コミッターのメールアドレスやプライベートリポジトリの名前などは、機密性が求められる場合があります。

いくつかのステップを踏むことで、GitHubから配信されるペイロードを安全に受信できます。

  1. 受信サーバーは必ずHTTPS接続にしてください。 デフォルトでは、GitHubはペイロードを配信する際にSSL証明書を検証します。
  2. ペイロードがGitHubから配信されていることを確実に保証するため、シークレットトークンを提供します。 シークレットトークンを強制することにより、サーバーが受信するあらゆるデータが確実にGitHubから来ていることを保証できます。 サービスのユーザごとに異なるシークレットトークンを提供するのが理想的です。 そうすれば、1つのトークンが侵害されても、他のユーザは影響を受けません。

同期作業より非同期作業を優先する

GitHubは、webhookペイロードを受信後30秒以内にインテグレーションが応答することを求めています。 サービスの応答時間がそれ以上になると、GitHubは接続を中止し、ペイロードは失われます。

サービスの完了時間を予測することは不可能なので、「実際の作業」のすべてはバックグラウンドジョブで実行すべきです。 バックグラウンドジョブのキューや処理を扱えるライブラリには、Resque (Ruby用)、RQ (Python用)、RabbitMQなどがあります。

バックグラウンドジョブが実行中でも、GitHubはサーバがthirty秒以内に応答することを求めていることに注意してください。 サーバは何らかの応答を送信することにより、ペイロードの受信を確認する必要があります。 サービスがペイロードについての確認を可能な限り速やかに行うことは非常に重要です。そうすることにより、サーバがリクエストを継続するかどうか正確に報告できます。

GitHubへの応答時に適切なHTTPステータスコードを使用する

各webhookには、デプロイメントが成功したかどうかを列挙する独自の「最近のデリバリ」セクションがあります。

[Recent Deliveries] ビュー

ユーザへの通知には、適切なHTTPステータスコードを使用するべきです。 (デフォルトでないブランチから配信されたペイロードなど) 処理できないペイロードの受信を知らせるため、201202といったコードを使用できます。 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にアクセスしようとするとき立て続けにエラーが発生することがるかもしれません。

繰り返し表示される4xx5xxのステータスコードを無視せずに、APIと正しくやり取りしていることを確認してください。 たとえば、エンドポイントが文字列を要求しているのに数値を渡している場合、5xx検証エラーが発生し、呼び出しは成功しません。 同様に、許可されていないエンドポイントまたはは存在しないエンドポイントにアクセスしようとすると、4xxエラーが発生します。

繰り返し発生する検証エラーを意図的に無視すると、不正利用によりアプリケーションが停止されることがあります。