Crafting a Great
Webhooks Experience
John Sheehan
CEO, @Runscope
Tuesday, October 7, 14
Slide 2
Slide 2 text
Tuesday, October 7, 14
Slide 3
Slide 3 text
Tuesday, October 7, 14
Slide 4
Slide 4 text
Tuesday, October 7, 14
Slide 5
Slide 5 text
Tuesday, October 7, 14
Slide 6
Slide 6 text
Tuesday, October 7, 14
Slide 7
Slide 7 text
"user defined
callbacks made
with HTTP POST"
Tuesday, October 7, 14
Slide 8
Slide 8 text
"Webhooks are the
easiest way to remotely
execute code."
-- Jeff Lindsay once
when we were talking
Tuesday, October 7, 14
Slide 9
Slide 9 text
HTTP Push
Notifications
Tuesday, October 7, 14
Slide 10
Slide 10 text
A Reverse API
Tuesday, October 7, 14
Slide 11
Slide 11 text
Provider makes request to
URL when an event happens.
Consumer sets up a server to
listen for callbacks.
Consumer registers callback
URL with provider.
Tuesday, October 7, 14
Slide 12
Slide 12 text
Provider makes request to
URL when an event happens.
Consumer sets up a server to
listen for callbacks.
Consumer registers callback
URL with provider.
Tuesday, October 7, 14
Slide 13
Slide 13 text
Provider makes request to
URL when an event happens.
Consumer sets up a server to
listen for callbacks.
Consumer registers callback
URL with provider.
Tuesday, October 7, 14
Slide 14
Slide 14 text
Tuesday, October 7, 14
Slide 15
Slide 15 text
Implementing
Webhooks
Tuesday, October 7, 14
Slide 16
Slide 16 text
url = get_callback_url()
data = get_webhook_payload_json()
try:
resp = requests.post(url, data=data)
if not resp.ok:
_logger.error(resp.content)
except Exception as e:
_logger.error(e)
Tuesday, October 7, 14
Slide 17
Slide 17 text
Problem #1:
Error Handling
Tuesday, October 7, 14
Slide 18
Slide 18 text
> POST /callback
< 400 Bad Request
Tuesday, October 7, 14
Slide 19
Slide 19 text
> POST /callback
< 302 Found
< Location: http://
Tuesday, October 7, 14
Slide 20
Slide 20 text
> POST /callback
< 200 OK
< Content-Type: text/plain
<
Tuesday, October 7, 14
Slide 21
Slide 21 text
Error Handling
Suggestions
Tuesday, October 7, 14
Slide 22
Slide 22 text
Be lenient in what you accept
back if you can reasonably guess.
Retry failed callbacks with
exponential back off.
Decide if redirects are to be
followed or not.
Tuesday, October 7, 14
Slide 23
Slide 23 text
Be lenient in what you accept
back if you can reasonably guess.
Retry failed callbacks with
exponential back off.
Decide if redirects are to be
followed or not.
Tuesday, October 7, 14
Slide 24
Slide 24 text
Be lenient in what you accept
back if you can reasonably guess.
Retry failed callbacks with
exponential back off.
Decide if redirects are to be
followed or not.
Tuesday, October 7, 14
Slide 25
Slide 25 text
Problem #2:
Flooding
Tuesday, October 7, 14
Slide 26
Slide 26 text
Tuesday, October 7, 14
Slide 27
Slide 27 text
Active
Queues
↪
↪
Tuesday, October 7, 14
Slide 28
Slide 28 text
Problem #3:
Security
Tuesday, October 7, 14
Slide 29
Slide 29 text
> POST http://localhost:3000
Tuesday, October 7, 14
Slide 30
Slide 30 text
> POST http://foo.lvh.me
Tuesday, October 7, 14
Slide 31
Slide 31 text
DoS Attack Vector
Tuesday, October 7, 14
Slide 32
Slide 32 text
Proving the Source
Tuesday, October 7, 14
Slide 33
Slide 33 text
Validation
Techniques
Tuesday, October 7, 14
Slide 34
Slide 34 text
Key Sharing
Tuesday, October 7, 14
Slide 35
Slide 35 text
Request
Signing
Tuesday, October 7, 14
Slide 36
Slide 36 text
Re-fetch
> POST /callback
> { id: 123 }
> GET /users/123
< { id: 123 }
Webhook Callback
App Code
Tuesday, October 7, 14
Slide 37
Slide 37 text
Security
Suggestions
Tuesday, October 7, 14
Slide 38
Slide 38 text
Validate your requests.
Document it well!
Resolve IPs before making
request. Consider proxying.
Consider subscription validation
for high-volume cases.
Tuesday, October 7, 14
Slide 39
Slide 39 text
Validate your requests.
Document it well!
Resolve IPs before making
request. Consider proxying.
Consider subscription validation
for high-volume cases.
Tuesday, October 7, 14
Slide 40
Slide 40 text
Validate your requests.
Document it well!
Resolve IPs before making
request. Consider proxying.
Consider subscription validation
for high-volume cases.
Tuesday, October 7, 14
Slide 41
Slide 41 text
Developer
Experience
Tuesday, October 7, 14
Slide 42
Slide 42 text
Payload Design
Tuesday, October 7, 14
Slide 43
Slide 43 text
Fat vs.Thin
Tuesday, October 7, 14
Slide 44
Slide 44 text
- or -
{ }
payload=
Tuesday, October 7, 14
Slide 45
Slide 45 text
- or -
data = JSON.loads(request.body)
name = data["name"]
name = request.form.get("name")
Tuesday, October 7, 14
Slide 46
Slide 46 text
payload = request.form.get("payload")
data = JSON.loads(payload)
name = data["name"]
Tuesday, October 7, 14
Slide 47
Slide 47 text
Mirror API
Resources
Tuesday, October 7, 14
Slide 48
Slide 48 text
Complete
Documentation!
Tuesday, October 7, 14
Slide 49
Slide 49 text
Tooling
Tuesday, October 7, 14
Slide 50
Slide 50 text
Accept Multiple
Callback URLs
Tuesday, October 7, 14