{"id":13393110,"url":"https://github.com/dunglas/vulcain","last_synced_at":"2025-05-14T04:07:29.080Z","repository":{"id":38433329,"uuid":"207353401","full_name":"dunglas/vulcain","owner":"dunglas","description":"🔨 Fast and idiomatic client-driven REST APIs.","archived":false,"fork":false,"pushed_at":"2025-04-22T13:43:34.000Z","size":3739,"stargazers_count":3534,"open_issues_count":22,"forks_count":104,"subscribers_count":52,"default_branch":"main","last_synced_at":"2025-04-22T14:43:32.756Z","etag":null,"topics":["api","early-hints","graphql","hacktoberfest","http2","http2-push","http3","hypermedia-api","preload","rest","rest-api","reverse-proxy","server-push","vulcain","vulcain-server"],"latest_commit_sha":null,"homepage":"https://vulcain.rocks","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dunglas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"dunglas"}},"created_at":"2019-09-09T16:24:00.000Z","updated_at":"2025-04-22T13:43:39.000Z","dependencies_parsed_at":"2024-01-12T20:57:48.962Z","dependency_job_id":"de56a159-19d7-4004-8786-b4b7420bd7b0","html_url":"https://github.com/dunglas/vulcain","commit_stats":{"total_commits":162,"total_committers":24,"mean_commits":6.75,"dds":0.5061728395061729,"last_synced_commit":"49a52652b9ce29ea00c7c6f4d28537f7cf217944"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Fvulcain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Fvulcain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Fvulcain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dunglas%2Fvulcain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dunglas","download_url":"https://codeload.github.com/dunglas/vulcain/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254069079,"owners_count":22009484,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","early-hints","graphql","hacktoberfest","http2","http2-push","http3","hypermedia-api","preload","rest","rest-api","reverse-proxy","server-push","vulcain","vulcain-server"],"created_at":"2024-07-30T17:00:43.426Z","updated_at":"2025-05-14T04:07:29.032Z","avatar_url":"https://github.com/dunglas.png","language":"Go","readme":"\u003ch1 align=\"center\"\u003e\u003cimg src=\"vulcain.svg\" alt=\"Vulcain: Use HTTP/2 Server Push to create fast and idiomatic client-driven REST APIs\" title=\"Use HTTP/2 Server Push to create fast and idiomatic client-driven REST APIs\"\u003e\u003c/h1\u003e\n\nVulcain is a brand new protocol using Preload hints and the `103 Early Hints` status code to create fast and idiomatic **client-driven REST** APIs.\n\nAn open source gateway server (a module for the [Caddy web server](https://caddyserver.com)), which you can put on top of **any existing web API** to instantly turn it into a Vulcain-compatible API is also provided!\n\nIt supports [hypermedia APIs](https://restfulapi.net/hateoas/) (e.g. any API created with [API Platform](https://api-platform.com)) but also any \"legacy\" API by documenting its relations [using OpenAPI](docs/gateway/openapi.md).\n\n[![Plant Tree](https://img.shields.io/badge/dynamic/json?color=brightgreen\u0026label=Plant%20Tree\u0026query=%24.total\u0026url=https%3A%2F%2Fpublic.offset.earth%2Fusers%2Ftreeware%2Ftrees)](https://plant.treeware.earth/dunglas/vulcain)\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/dunglas/vulcain/gateway)](https://pkg.go.dev/github.com/dunglas/vulcain)\n[![Build Status](https://github.com/dunglas/vulcain/workflows/CI/badge.svg)](https://github.com/dunglas/vulcain/actions)\n[![codecov](https://codecov.io/gh/dunglas/vulcain/branch/master/graph/badge.svg)](https://codecov.io/gh/dunglas/vulcain)\n[![Go Report Card](https://goreportcard.com/badge/github.com/dunglas/vulcain)](https://goreportcard.com/report/github.com/dunglas/vulcain)\n\n[tabs]\n\n### Preload\n![Vulcain Schema](schemas/vulcain_doc_main_200.png)\n\n### Preload + Early Hints\n![Vulcain Schema](schemas/vulcain_doc_main_early_hints.png)\n\n### Server push\n![Vulcain Schema](schemas/vulcain_doc_main_server_push.png)\n\n[/tabs]\n\nGrab What You Need... Burn The REST!\n\n* [Introduction](#introduction)\n  * [Pushing Relations](#pushing-relations)\n  * [Filtering Resources](#filtering-resources)\n* [Gateway Server](docs/gateway/)\n  * [Caddy Web Server Module](docs/gateway/caddy.md)\n  * [Mapping a Non-Hypermedia API using OpenAPI](docs/gateway/openapi.md)\n  * [Legacy Standalone Server](docs/gateway/install.md)\n  * [Legacy Configuration](docs/gateway/config.md)\n* [Comparison with GraphQL and Other API Formats](docs/graphql.md)\n* [Using GraphQL as Query Language for Vulcain](docs/graphql.md#using-graphql-as-query-language-for-vulcain)\n* [Demo API](CONTRIBUTING.md)\n* [Cache Considerations](docs/cache.md)\n* [Formal Specification](spec/vulcain.md)\n* [Getting Help](docs/help.md)\n\nThe protocol has been published as [an Internet Draft](https://datatracker.ietf.org/doc/draft-dunglas-vulcain/) that [is maintained in this repository](spec/vulcain.md).\n\nA reference, production-grade, implementation [**gateway server**](docs/gateway/caddy.md) is also available in this repository.\nIt's free software (AGPL) written in Go. A Docker image is provided.\n\n## Introduction\n\nOver the years, several formats have been created to fix performance bottlenecks impacting web APIs: [over fetching, under fetching](https://stackoverflow.com/a/44568365/1352334), [the n+1 problem](https://restfulapi.net/rest-api-n-1-problem/)...\n\n[Current solutions for these problems (GraphQL, JSON:API's embedded resources and sparse fieldsets, ...)](docs/graphql.md) are smart [network hacks](https://apisyouwonthate.com/blog/lets-stop-building-apis-around-a-network-hack) for HTTP/1. But these hacks come with (too) many drawbacks when it comes to HTTP cache, logs and even security.\n\nFortunately, thanks to the new features introduced in HTTP/2, it's now possible to create true REST APIs fixing these problems with ease and class! Here comes Vulcain!\n\nSee also [the comparison between Vulcain and GraphQL and other API formats](docs/graphql.md).\n\n## Pushing Relations\n\n[tabs]\n\n### Preload\n![Preload Schema](schemas/vulcain_doc_preload_200.png)\n\n### Preload + Early Hints\n![Preload Schema](schemas/vulcain_doc_preload_early_hints.png)\n\n### Server push\n![Preload Schema](schemas/vulcain_doc_preload_server_push.png)\n\n[/tabs]\n\nConsidering the following resources:\n\n`/books`\n\n```json\n{\n    \"member\": [\n        \"/books/1\",\n        \"/books/2\"\n    ]\n}\n```\n\n`/books/1`\n\n```json\n{\n    \"title\": \"1984\",\n    \"author\": \"/authors/1\"\n}\n```\n\n`/books/2`\n\n```json\n{\n    \"title\": \"Homage to Catalonia\",\n    \"author\": \"/authors/1\"\n}\n```\n\n`/authors/1`\n\n```json\n{\n    \"givenName\": \"George\",\n    \"familyName\": \"Orwell\"\n}\n```\n\nThe `Preload` HTTP header introduced by Vulcain can be used to ask the server to immediately push resources related to the requested one using 103 Early Hints or HTTP/2 Server Push:\n\n```http\nGET /books/ HTTP/2\nPreload: \"/member/*/author\"\n```\n\nIn addition to `/books`, a Vulcain server will push the `/books/1`, `/books/2` and `/authors/1` resources!\n\nExample in JavaScript:\n\n```javascript\nconst bookResp = await fetch(\"/books/1\", { headers: { Preload: `\"/author\"` } });\nconst bookJSON = await bookResp.json();\n\n// Returns immediately, the resource has been pushed and is already in the push cache\nconst authorResp = await fetch(bookJSON.author);\n// ...\n```\n\n[Full example, including collections](fixtures/static/main.js), see also [use GraphQL as query language for Vulcain](docs/graphql.md#using-graphql-as-query-language-for-vulcain).\n\nThanks to [HTTP/2+ multiplexing](https://stackoverflow.com/a/36519379/1352334), pushed responses will be sent in parallel.\n\nWhen the client will follow the links and issue a new HTTP request (for instance using `fetch()`), the corresponding response will already be in cache, and will be used instantly!\n\nFor non-hypermedia APIs (when the identifier of the related resource is a simple string or int), [use an OpenAPI specification to configure links between resources](docs/gateway/openapi.md).\nTip: the easiest way to create a hypermedia API is to use [the API Platform framework](https://api-platform.com) (by the same author as Vulcain).\n\nWhen possible, we recommend using [Early Hints](https://tools.ietf.org/html/rfc8297) (the 103 HTTP status code) to push the relations.\nVulcain allows to gracefully fallback to [`preload` links](https://www.w3.org/TR/preload/) in the headers of the final response or to [HTTP/2 Server Push](https://tools.ietf.org/html/rfc7540#section-10.1) when the 103 status code isn't supported.\n\n### Query Parameter\n\nAlternatively to HTTP headers, the `preload` query parameter can be used:\n\n[tabs]\n\n#### Preload\n![Preload Query Schema](schemas/vulcain_doc_preload_query_200.png)\n\n#### Preload + Early Hints\n![Preload Query Schema](schemas/vulcain_doc_preload_query_early_hints.png)\n\n#### Server push\n![Preload Query Schema](schemas/vulcain_doc_preload_query_server_push.png)\n\n[/tabs]\n\n## Filtering Resources\n\n[tabs]\n\n### Preload\n![Filter Schema](schemas/vulcain_doc_filter_200.png)\n\n### Preload + Early Hints\n![Filter Schema](schemas/vulcain_doc_filter_early_hints.png)\n\n### Server push\n![Filter Schema](schemas/vulcain_doc_filter_server_push.png)\n\n[/tabs]\n\nThe `Fields` HTTP header allows the client to ask the server to return only the specified fields of the requested resource, and of the preloaded related resources.\n\nMultiple `Fields` HTTP headers can be passed. All fields matching at least one of these headers will be returned. Other fields of the resource  will be omitted.\n\nConsidering the following resources:\n\n`/books/1`\n\n```json\n{\n    \"title\": \"1984\",\n    \"genre\": \"novel\",\n    \"author\": \"/authors/1\"\n}\n```\n\n`/authors/1`\n\n```json\n{\n    \"givenName\": \"George\",\n    \"familyName\": \"Orwell\"\n}\n```\n\nAnd the following HTTP request:\n\n```http\nGET /books/1 HTTP/2\nPreload: \"/author\"\nFields: \"/author/familyName\", \"/genre\"\n```\n\nA Vulcain server will return a response containing the following JSON document:\n\n```json\n{\n    \"genre\": \"novel\",\n    \"author\": \"/authors/1\"\n}\n```\n\nIt will also push the following filtered `/authors/1` resource:\n\n```json\n{\n    \"familyName\": \"Orwell\"\n}\n```\n\n### Query Parameter\n\nAlternatively to HTTP headers, the `fields` query parameter can be used to filter resources:\n\n[tabs]\n\n#### Preload\n![Fields Schema](schemas/vulcain_doc_filter_query_200.png)\n\n#### Preload + early hints\n![Fields Schema](schemas/vulcain_doc_filter_query_early_hints.png)\n\n#### Server push\n![Fields Schema](schemas/vulcain_doc_filter_query_server_push.png)\n\n[/tabs]\n\n## See Also\n\n* [Mapping a non-hypermedia API using OpenAPI](docs/gateway/openapi.md)\n* [Cache considerations](docs/cache.md)\n* [Using GraphQL with Vulcain](docs/graphql.md#using-graphql-as-query-language-for-vulcain)\n* [Using other selectors such as XPath and CSS selectors for non-JSON documents](spec/vulcain.md#selectors) (only JSON Pointer [is currently supported](https://github.com/dunglas/vulcain/issues/3) by the Gateway Server)\n\n## License and Copyright \n\ntl;dr:\n\n* proprietary software **can** implement the Vulcain specification\n* proprietary software **can** be used behind the Vulcain Gateway Server without having to share their sources\n* modifications made to the Vulcain Gateway Server **must** be shared\n* alternatively, a commercial license is available for the Vulcain Gateway Server\n\n[The specification](spec/vulcain.md) is available under [the IETF copyright policy](https://trustee.ietf.org/copyright-faq.html). The Vulcain **specification** can be implemented by any software, including proprietary software.\n\nThe Vulcain Gateway Server is licensed under [AGPL-3.0](LICENSE). This license implies that if you modify the Vulcain Gateway Server, you must share those modifications. However, the AGPL-3.0 license applies only to the gateway server itself, **not to software used behind the gateway**.\n\nFor companies not wanting, or not able to use AGPL-3.0 licensed software, commercial licenses are also available. [Contact us for more information](mailto:kevin+vulcain@dunglas.dev).\n\n## Treeware\n\nThis package is [Treeware](https://treeware.earth). If you use it in production, then we ask that you [**buy the world a tree**](https://plant.treeware.earth/dunglas/vulcain) to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats.\n\n## Credits\n\nCreated by [Kévin Dunglas](https://dunglas.dev). Sponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop).\n\nSome ideas and code used in Vulcain's reference implementation have been taken from [Hades](https://github.com/gabesullice/hades) by [Gabe Sullice](https://github.com/gabesullice), an HTTP/2 reverse proxy for JSON:API backend.\n\nSee also [the prior arts](docs/prior-art.md).\n","funding_links":["https://github.com/sponsors/dunglas"],"categories":["Go","api"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdunglas%2Fvulcain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdunglas%2Fvulcain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdunglas%2Fvulcain/lists"}