Vulcain: HTTP/2 Server Push
 and the rise of client-driven REST APIs

Vulcain: HTTP/2 Server Push
 and the rise of client-driven REST APIs

Over the years, several formats have been created to fix performance bottlenecks of web APIs: the n+1 problem, over fetching, under fetching…
The current hipster solution for these problems is to replace the conceptual model of HTTP (resource-oriented), by the one of GraphQL.

It’s a smart network hack for HTTP/1… But a hack that comes with (too) many drawbacks when it comes to HTTP cache, logs, security…
Fortunately, thanks to the new features introduced in HTTP/2 and HTTP/3, it’s now possible to create REST APIs fixing these problems with ease and class.

Vulcain is a brand new Internet Draft allowing to create fast, idiomatic and client-driven REST APIs.
To do so, it relies on the Server Push feature introduced by HTTP/2+ and on the hypermedia capabilities of the HTTP protocol.

Better, Vulcain comes with an open source reverse proxy that you can put on top of any existing web API to instantly turn it into a Vulcain-compatible one!

HATEOAS is back, and it’s for the best!

Demo repository:


Kévin Dunglas

November 21, 2019


  1. 2.

    @dunglas - Kévin Dunglas ❏ Founder of ❏

    Creator of,, API Platform… ❏ Symfony Core Team Member @dunglas @ .social
  2. 3.

    @dunglas - API, cloud, PHP and JS experts ✊

    Self-managed, 100% employee-owned 45 people, 1,000% growth in 6 years
  3. 5.

    @dunglas - « REST was developed […] primarily as

    a means for communicating Web concepts as we wrote the HTTP/1.0 specification and the initial HTTP/1.1 proposal. »
 - Roy T. Fielding
  4. 6.

    @dunglas - REST: the Architectural Style of the Web

    ❏ client-server ❏ resource oriented ❏ stateless ❏ cacheable by clients and intermediaries ❏ layered (gateways and proxies) ❏ uniform interface (URI, HATEOAS…)
  5. 9.

    @dunglas - REST Performance ❏ REST is designed to

    solve performance and scalability problems at internet-scale ❏ REST relies on a powerful caching model: clients and intermediates can cache ❏ HTTP implements this model © Google
  6. 10.

    @dunglas - The Under-Fetching and the N+1 Problems Not

    fetching enough data initially forces to issue subsequent requests, so creates waterfalls and increase latency. © Expedia Group
  7. 11.

    @dunglas - The Over-Fetching Problem Generating and fetching too

    much data (data not used by clients) wastes bandwidth and computation power.
  8. 12.
  9. 14.

    @dunglas - HTTP/2: Making the Web Faster ❏ Binary

    protocol, multiplexing, prioritization ❏ Server Push of resources ❏ Headers compression ❏ HTTP/3: good bye TCP (perf, again)
  10. 20.
  11. 22.

    @dunglas - Consuming Pushes in JavaScript const outboxResp =

    await fetch( "/outbox", { headers: { Preload: "/orderedItems/*/object" } } ); const outbox = await outboxResp.json(); outboxJSON.orderedItems.forEach(async activityURL => { // Returns immediately,
 // the resource has been pushed and is already in the push cache const activityResp = await fetch(activityURL); const activity = await activityResp.json(); // Returns immediately too const statusResp = await fetch(activity.object); // Do something with the status response... });
  12. 23.

    @dunglas - Benefits ❏ Fixes the under-fetching and N+1

    problems ❏ Resources are downloaded in parallel (multiplexing) ❏ Granular HTTP cache (download only what isn’t in cache) ❏ Respects REST principles ❏ Leverages all features of the HTTP protocol ❏ cache, authorization, content negotiation, extensibility…
  13. 25.

    @dunglas - Other Capabilities ❏ Selector negotiation: ❏ extended

    JSON Pointer, XPath, CSS selectors, JMESPath… ❏ Support using Link preload headers and103 Early Hints as a fallback (cross-domain resources, HTTP/1…) ❏ Use query parameters instead of HTTP headers ❏ Support non-hypermedia APIs through OpenAPI
  14. 27.

    @dunglas - The Vulcain Gateway Server ❏ Instantly turns

    any existing hypermedia or non-hypermedia API into a Vulcain-enabled API ❏ Gateway server (plug’n’play network intermediate) ❏ Free software (open source) ❏ Fast, written in Go ❏ Easy to install (static binary, Docker image) ❏ Best performance: implement the protocol directly at the app server layer
  15. 30.

    @dunglas - Mapping a « Legacy » API #

    openapi.yaml openapi: 3.0.0 # ... paths: '/books/{id}': get: # ... responses: default: links: author: operationId: getAuthor parameters: id: '$response.body#/author' '/authors/{id}': get: operationId: getAuthor responses: default: # ... // /books/1984 { "title": "1984", "author": 1 // Not an URI } // /authors/1 { "givenName": "George", "familyName": "Orwell" }
  16. 32.

    @dunglas - Vulcain vs GraphQL: Performance ❏ Unlike GraphQL,

    Vulcain sends each pushed resource in a separate HTTP/2 stream (multiplexing): related resources are sent in parallel ❏ Embedding resources is a forced push: the client receive the full JSON documents, even if it already has some parts of it ❏ With Vulcain, clients can cancel the push of resources they already have, saving bandwidth and improving performance
  17. 33.

    @dunglas - But GraphQL is More Than That! ❏

    Query Language ❏ Type System ❏ Introspection ❏ Subscriptions ❏ Great tooling
  18. 34.

    @dunglas - Type System and Introspection REST has that

    too… and a bit more! ❏ JSON-LD: internet-scale type system,
 built on top of RDF, W3C ❏ Hydra: hypermedia introspection system,
 built on top of JSON-LD, W3C ❏ OpenAPI: type system and introspection
  19. 35.

    @dunglas - { "@context": "", "type": "Person", "id": "https://social.example/alyssa/",

    "name": "Alyssa P. Hacker", "preferredUsername": "alyssa", "summary": "Lisp enthusiast hailing from MIT", "inbox": "https://social.example/alyssa/inbox/", "outbox": "https://social.example/alyssa/outbox/", "followers": "https://social.example/alyssa/followers/", "following": "https://social.example/alyssa/following/", "liked": "https://social.example/alyssa/liked/" }
  20. 37.

    @dunglas - Tooling ❏ GraphQL provides great client-side tooling

    and an unified Developer Experience, REST is still behind ❏ But because GraphQL uses HTTP as a black box: ❏ HTTP Cache servers (Varnish, Nginx…) ❏ standard WAF (ModSecurity…) ❏ HTTP logs analyzer (GoAccess, AWStats…) ❏ API Gateways (Kong, Gravitee…) are almost useless
  21. 38.

    @dunglas - Tooling REST also has modern, easy to

    use client-side and server-side tooling: ❏ API Platform (PHP & JS): create JSON-LD APIs and smart React & Vue PWA, admin UIs, etc… in minutes! ❏ Graphiti (Ruby On Rails): create REST APIs in minutes ❏ Zeit’s SWR: React Hooks library for HTTP APIs leveraging concurrent rendering (perfect Vulcain’s companion) Vulcain works out of the box with all these tools!
  22. 39.

    @dunglas - Using GraphQL to Query a Vulcain Server

    ❏ GraphQL is a convenient Query Language for APIs ❏ Write GraphQL queries client-side, and benefit from all the GQL ecosystem ❏ Use apollo-link-rest to convert the GQL query in a single REST+Vulcain request to the server Best of both worlds?
  23. 41.
  24. 43.
  25. 44.

    @dunglas - « The Web is intended to be

    an Internet-scale distributed hypermedia system […]. The Internet is about interconnecting information networks across multiple organizational boundaries. »
 - Roy T. Fielding
  26. 45.

    @dunglas - The Threat of Data Centralization ❏ Facebook,

    Microsoft, Google, Apple… participated to NSA’s PRISM global mass surveillance program ❏ Cambridge Analytica manipulated the US election using Facebook data ❏ Facebook blocks pages of Kurdish organizations fighting ISIS ❏ GitHub blocks all Iranian users, including famous OSS contributors ❏ GitHub banned Tsunami Democràtic's app (pro Catalan-independence) Data centralization is harmful!
  27. 46.
  28. 47.

    @dunglas - REST /
 Linked Data GraphQL server Origin

    Scientific community, to serve humanity Facebook, to serve its business Data access « Internet as a global database » Centralized information silos Interoperability Global and built-in Partial Best suited for Distributed systems Public APIs (« Open Data ») The World Wide Web Centralized systems Internal APIs
  29. 48.

    @dunglas - // https://social.example/alyssa/posts/123 { "@context": "", "type": "Note",

    // Not possible with a GraphQL server "to": ["https://chatty.example/ben/"], // reference to an external organization "attributedTo": "https://social.example/alyssa/", "content": "Say, did you finish reading that book I lent you?" } The power of Vulcain: GET https://social.example/alyssa/posts/123 Preload: /to Fields: /to, /content // Some hope for GraphQL? GraphQL-LD, HyperGraphQL: GQL as a query language for RDF
  30. 50.

    @dunglas - The Rise of the Dweb REST, JSON-LD,, RDF, ActivityPub… ❏ Solid (by T. Berners-Lee): web decentralization, privacy by design ❏ : federated social network ❏ Mobilizon: federated Meetup-like ❏ PeerTube: federated video-streaming service ❏ NextCloud: federated file sharing service Vulcain works out of the box with all of them!
  31. 52.

    @dunglas - Vulcain, Symfony and API Platform The project:

    ❏ an app to send feedback to speakers, as in Lisbon 2018 The stack: ❏ Symfony + API Platform ❏ JSON-LD ❏ Varnish ❏ Vulcain
  32. 53.

    @dunglas - The API Platform Distribution ❏ PHP +

    Symfony + API Platform ❏ Vulcain (master branch only) ❏ Varnish ❏ Postgres ❏ Docker and Kubernetes config
  33. 55.

    @dunglas - Our Vulcain API is Ready! A fully-featured

    API for the Dweb: ❏ JSON-LD + Hydra + ❏ Vulcain ❏ Varnish ❏ Mercure, auth, pagination, filters, validation, test framework, admin, React/Vue.js/Next.js generators…
  34. 56.

    @dunglas - Benchmark ❏ Inject fixtures (using Alice) ❏

    10 conferences ❏ 100 sessions ❏ 100 feedback ❏ Fetch all the resources client-side
  35. 57.

    @dunglas - Benchmark // Load ALL data from the

    API // Simulate more data dependencies than they really exist
 // to increase the waterfall effect console.time('download'); const conferences = await fetchJson('/conferences', { headers: { Preload: ‘/hydra:member/*/@id/ sessions/*/feedback/*' }}); for (const conferenceRel of conferences['hydra:member']) { const conference = await fetchJson(conferenceRel['@id']); // Fetch sessions for (const sessionURL of conference.sessions) { const session = await fetchJson(sessionURL); // Fetch feedback for (const feedbackURL of { const feedback = await fetchJson(feedbackURL) } } } console.timeEnd('download');
  36. 58.

    @dunglas - Results: Vulcain kills the Waterfall effect ❏

    No Varnish, No Vulcain: 22,152 ms ❏ No Varnish, Vulcain: 9,704 ms ❏ Varnish, No Vulcain: 783 ms ❏ Varnish + Vulcain: 524ms ❏ Vulcain is 2.3x faster than API Platform without Vulcain ❏ Varnish is 28x faster than API Platform without Varnish ❏ The combination of Varnish and Vulcain is 42x faster than API Platform without Varnish, and without Vulcain ❏ The combination of Varnish and Vulcain is 1.5x faster than Varnish alone!
  37. 61.

    @dunglas - Summary Vulcain is: ❏ Fast (faster than

    GraphQL and JSON:API includes) ❏ Designed for the open web and interoperability at Internet-scale ❏ Easy to deploy ❏ Compatible with most existing tools ❏ Swagger/OpenAPI, log analyzers, Varnish, WAF, RDF… ❏ Can be supported in minutes by any web API ❏ including legacy RESTish APIs thanks to its OpenAPI support ❏ You can even use GraphQL to query a Vulcain API! Give it a try!