You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/guides/best-practices-for-integrators.md
+59-22Lines changed: 59 additions & 22 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,7 +10,7 @@ Interested in integrating with the GitHub platform? [You're in good company](htt
10
10
11
11
## Secure payloads delivered from GitHub
12
12
13
-
It's very important that you secure [the payloads sent from GitHub](/v3/activity/events/types/). Although no personal information (like passwords) is ever transmitted in a payload, leaking *any* information is not good. Some information that might be sensitive include committer email address or the names of private repositories.
13
+
It's very important that you secure [the payloads sent from GitHub][event-types]. Although no personal information (like passwords) is ever transmitted in a payload, leaking *any* information is not good. Some information that might be sensitive include committer email address or the names of private repositories.
14
14
15
15
There are three steps you can take to secure receipt of payloads delivered by GitHub:
16
16
@@ -54,38 +54,73 @@ For the stability of your app, you shouldn't try to parse this data or try to gu
54
54
55
55
For example, when working with paginated results, it's often tempting to construct URLs that append `?page=<number>` to the end. Avoid that temptation. [Our guide on pagination](/guides/traversing-with-pagination) offers some safe tips on dependably following paginated results.
56
56
57
-
## Check the action before processing the event
58
-
Webhook events can have multiple actions. As GitHub's feature set grows, we will occasionally add new actions to existing event types. Ensure that your application explicitly checks the action before doing any processing. For example, the [`IssuesEvent`](https://developer.github.com/v3/activity/events/types/#issuesevent) has several possible actions, such as `opened` when the issue is created, `closed` when the issue is closed, and `assigned` when the issue is assigned to someone.
57
+
## Check the event type and action before processing the event
59
58
60
-
Two code examples are given below, Fig 1.1 and Fig 1.2. In Fig 1.1, the `process_closed` method will be called for any event action which is not `opened` or `assigned`. This means that the `process_closed` method will be called for events with the `closed` action, but also other events with different actions delivered to the webhook.
59
+
There are multiple [webhook event types][event-types], and each event can have multiple actions. As GitHub's feature set grows, we will occasionally add new event types or add new actions to existing event types. Ensure that your application explicitly checks the type and action of an event before doing any webhook processing. The `X-GitHub-Event` request header can be used to know which event has been received so that processing can be handled appropriately. Similarly, the payload has a top-level `action` key that can be used to know which action was taken on the relevant object.
61
60
62
-
Instead, the suggested approach is to explicitly check event actions and act accordingly such as in Fig 1.2. In this example the `closed` action is checked first before calling the `process_closed` method.
61
+
For example, if you have configured a GitHub webhook to "Send me **everything**", your application will begin receiving new event types and actions as they are added. It is therefore **not recommended to use any sort of catch-all else clause**. Take the following code example:
63
62
64
-
**Fig 1.1: Not Recommended: catch-all else block**
65
63
```ruby
66
-
case action
67
-
when"opened"
68
-
process_opened
69
-
when"assigned"
70
-
process_assigned
71
-
else
72
-
process_closed
64
+
# Not recommended: a catch-all else clause
65
+
defreceive
66
+
event_type = request.headers["X-GitHub-Event"]
67
+
payload = request.body
68
+
69
+
case event_type
70
+
when"repository"
71
+
process_repository(payload)
72
+
when"issues"
73
+
process_issues(payload)
74
+
else
75
+
process_pull_requests
76
+
end
73
77
end
74
78
```
75
79
76
-
**Fig 1.2: Recommended: explicitly check each action**
80
+
In this code example, the `process_repository` and `process_issues` methods will be correctly called if a `repository` or `issues` event was received. However, any other event type would result in `process_pull_requests` being called. As new event types are added, this would result in incorrect behavior and new event types would be processed in the same way that a `pull_request` event would be processed.
81
+
82
+
Instead, we suggest explicitly checking event types and acting accordingly. In the following code example, we explicitly check for a `pull_request` event and the `else` clause simply logs that we've received a new event type:
83
+
77
84
```ruby
78
-
case action
79
-
when"opened"
80
-
process_opened
81
-
when"assigned"
82
-
process_assigned
83
-
when"closed"
84
-
process_closed
85
+
# Recommended: explicitly check each event type
86
+
defreceive
87
+
event_type = request.headers["X-GitHub-Event"]
88
+
payload =JSON.parse(request.body)
89
+
90
+
case event_type
91
+
when"repository"
92
+
process_repository(payload)
93
+
when"issues"
94
+
process_issue(payload)
95
+
when"pull_request"
96
+
process_pull_requests(payload)
97
+
else
98
+
puts"Oooh, something new from GitHub: #{event_type}"
99
+
end
85
100
end
86
101
```
87
102
88
-
We may also add new webhook event types from time to time. If your webhook is configured to "Send me everything" then your code should also explicitly check for the event type in a similar way as we have done with checking for the action type above.
103
+
Because each event can also have multiple actions, it's recommended that actions are checked similarly. For example, the [`IssuesEvent`](https://developer.github.com/v3/activity/events/types/#issuesevent) has several possible actions. These include `opened` when the issue is created, `closed` when the issue is closed, and `assigned` when the issue is assigned to someone.
104
+
105
+
As with adding event types, we may add new actions to existing events. It is therefore again **not recommended to use any sort of catch-all else clause** when checking an event's action. Instead, we suggest explicitly checking event actions as we did with the event type. An example of this looks very similar to what we suggested for event types above:
106
+
107
+
```ruby
108
+
# Recommended: explicitly check each action
109
+
defprocess_issue(payload)
110
+
case payload["action"]
111
+
when"opened"
112
+
process_issue_opened(payload)
113
+
when"assigned"
114
+
process_issue_assigned(payload)
115
+
when"closed"
116
+
process_issue_closed(payload)
117
+
else
118
+
puts"Oooh, something new from GitHub: #{payload["action"]}"
119
+
end
120
+
end
121
+
```
122
+
123
+
In this example the `closed` action is checked first before calling the `process_closed` method. Any unidentified actions are logged for future reference.
89
124
90
125
## Dealing with rate limits
91
126
@@ -119,3 +154,5 @@ Although your code would never introduce a bug, you may find that you've encount
119
154
Rather than ignore repeated `4xx` and `5xx` status codes, you should ensure that you're correctly interacting with the API. For example, if an endpoint requests a string and you're passing it a numeric value, you're going to receive a `5xx` validation error, and your call won't succeed. Similarly, attempting to access an unauthorized or nonexistent endpoint will result in a `4xx` error.
120
155
121
156
Intentionally ignoring repeated validation errors may result in the suspension of your app for abuse.
0 commit comments