Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Date Lessons from integrating 1,500 APIs WebCore - September 24, 2019

Slide 3

Slide 3 text

Fokke Zandbergen Full Stack Engineer fokkezb.nl ❋ twitter.com/fokkezb ❋ linkedin.com/in/fokkezb ❋ github.com/fokkezb Fokke Zandbergen

Slide 4

Slide 4 text

About Zapier

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Milestones • • September 2011: Idea • May 2012: Y Combinator Graduation • September 2012: Raised $1.3M • May 2014: Profitable • June 2016: At 1M Users, $10M ARR • August 2017: At 100 Zapiens (or Zorps) • January 2018: At 1K Apps, $35M ARR • January 2019: At 1,5K Apps, $50M ARR

Slide 7

Slide 7 text

But what does it do?!

Slide 8

Slide 8 text

… or in developer speak

Slide 9

Slide 9 text

User Experience

Slide 10

Slide 10 text

Developer Experience

Slide 11

Slide 11 text

… or using the SDK

Slide 12

Slide 12 text

What makes an API easy to integrate with Zapier?

Slide 13

Slide 13 text

Don’t reinvent the wheel • • REST JSON • OAuth 2.0 (w/refresh) • REST Hooks * • OpenAPI *

Slide 14

Slide 14 text

Don’t save on docs to be... • • There • Complete • Versioned • Public * • Standard (OpenAPI / Swagger)

Slide 15

Slide 15 text

• They should never expire… • ...unless we have a refresh token • (which should never expire) • ...unless the user revokes it. We encrypt and censor them, please do so to. Secret tokens are Sacred •

Slide 16

Slide 16 text

• Limiting: number | timestamp • Pagination: (number | token) & meta • Filtering & Searching • Field Masks: fields GraphQL via the SDK: yarn add apollo-boost cross-fetch Work that body!

Slide 17

Slide 17 text

• Field: created_at • Direction: DESC Assuming the above, what will go wrong here? ?limit=10 &is_published=true Orderrrr!

Slide 18

Slide 18 text

• Field: id • Composite Fields: obj.object_id = obj.id; obj.id = hash([id,updated_at]); What else is new? •

Slide 19

Slide 19 text

• Please call us. We’ll only call you once. POST you.com/subscribe?url=zapier.com/1d2x • Better UX than (static) webhooks (+24%) • Reduces server load & traffic (-98.5%) • Triggers Zaps instantly Required for public apps resthooks.org Get Hooked!

Slide 20

Slide 20 text

HTTP/1.0 200 OK Content-Type: application/json { "status": "error", "code": 404, "message": "Object is not found." } HTTP Status Codes have a purpose

Slide 21

Slide 21 text

… as do HTTP Methods GET /api/book?title=APIs+For+Dummies HTTP/1.0 201 Created Content-Type text/plain Created “APIs For Dummies”

Slide 22

Slide 22 text

… and Content-Type HTTP/1.0 400 Bad Request Content-Type: application/json Parameter 'id' is missing. GET /books Accept: application/json HTTP/1.0 401 Unauthorized Content-Type: text/html Login ...

Slide 23

Slide 23 text

How to have millions of conversations with 1,500 apps… daily?

Slide 24

Slide 24 text

Polling Triggers • Shedding: Skip % of regular polling request • Deduplication (simplified pseudo) hash = md5(obj.id) ZADD(zapId, hash) ZSCAN(zapId, hash) • Held Tasks: This… can’t be right… right?

Slide 25

Slide 25 text

1. Response always written to S3 for (manual) replay. 2. First pass by trigger integration to parse response. After that, same for polling triggers: 3. For each object, write state to ES. 4. Queue first/next step for worker boxes. 5. Worker passes state to step trigger/action. 6. Write updated state and GOTO 4 Webhook Triggers

Slide 26

Slide 26 text

• Integrations are NodeJS apps. • Generated AWS Lambda function for each app version. • Lambda called to run trigger or action. output = createOrder(z, { auth, input }); • Bound to AWS limits for size of the app (50MB), payload (6MB) and time to complete (30 seconds). Running Integration Code

Slide 27

Slide 27 text

• Each integration sandboxed. • Only access to data mapped to the action’s input fields. • No binary data, just public (!) URLs to download data. publicUrl = z.stash(z.request(privateUrl)) • Credentials stored, encrypted, on a separate MS. • Credentials and token-like string censored in logs. Security

Slide 28

Slide 28 text

Thank you!

Slide 29

Slide 29 text

Is This You? Python React Scaling for 10x RabbitMQ SQL Django k8s empathy Redis default to action GraphQL Next.js Flow Typescript Node

Slide 30

Slide 30 text

Join us. From anywhere. zapier.com/jobs