Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/dunglas/vulcain

Fast and idiomatic client-driven REST APIs.
https://github.com/dunglas/vulcain

api early-hints graphql hacktoberfest http2 http2-push http3 hypermedia-api preload rest rest-api reverse-proxy server-push vulcain vulcain-server

Last synced: 19 days ago
JSON representation

Fast and idiomatic client-driven REST APIs.

Awesome Lists containing this project

README

        

Vulcain: Use HTTP/2 Server Push to create fast and idiomatic client-driven REST APIs

Vulcain is a brand new protocol using Preload hints and the `103 Early Hints` status code to create fast and idiomatic **client-driven REST** APIs.

An 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!

It 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).

[![Plant Tree](https://img.shields.io/badge/dynamic/json?color=brightgreen&label=Plant%20Tree&query=%24.total&url=https%3A%2F%2Fpublic.offset.earth%2Fusers%2Ftreeware%2Ftrees)](https://plant.treeware.earth/dunglas/vulcain)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/dunglas/vulcain/gateway)](https://pkg.go.dev/github.com/dunglas/vulcain)
[![Build Status](https://github.com/dunglas/vulcain/workflows/CI/badge.svg)](https://github.com/dunglas/vulcain/actions)
[![codecov](https://codecov.io/gh/dunglas/vulcain/branch/master/graph/badge.svg)](https://codecov.io/gh/dunglas/vulcain)
[![Go Report Card](https://goreportcard.com/badge/github.com/dunglas/vulcain)](https://goreportcard.com/report/github.com/dunglas/vulcain)

[tabs]

### Preload
![Vulcain Schema](schemas/vulcain_doc_main_200.png)

### Preload + Early Hints
![Vulcain Schema](schemas/vulcain_doc_main_early_hints.png)

### Server push
![Vulcain Schema](schemas/vulcain_doc_main_server_push.png)

[/tabs]

Grab What You Need... Burn The REST!

* [Introduction](#introduction)
* [Pushing Relations](#pushing-relations)
* [Filtering Resources](#filtering-resources)
* [Gateway Server](docs/gateway/)
* [Caddy Web Server Module](docs/gateway/caddy.md)
* [Mapping a Non-Hypermedia API using OpenAPI](docs/gateway/openapi.md)
* [Legacy Standalone Server](docs/gateway/install.md)
* [Legacy Configuration](docs/gateway/config.md)
* [Comparison with GraphQL and Other API Formats](docs/graphql.md)
* [Using GraphQL as Query Language for Vulcain](docs/graphql.md#using-graphql-as-query-language-for-vulcain)
* [Demo API](CONTRIBUTING.md)
* [Cache Considerations](docs/cache.md)
* [Formal Specification](spec/vulcain.md)
* [Getting Help](docs/help.md)

The 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).

A reference, production-grade, implementation [**gateway server**](docs/gateway/caddy.md) is also available in this repository.
It's free software (AGPL) written in Go. A Docker image is provided.

## Introduction

Over 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/)...

[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.

Fortunately, 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!

See also [the comparison between Vulcain and GraphQL and other API formats](docs/graphql.md).

## Pushing Relations

[tabs]

### Preload
![Preload Schema](schemas/vulcain_doc_preload_200.png)

### Preload + Early Hints
![Preload Schema](schemas/vulcain_doc_preload_early_hints.png)

### Server push
![Preload Schema](schemas/vulcain_doc_preload_server_push.png)

[/tabs]

Considering the following resources:

`/books`

```json
{
"member": [
"/books/1",
"/books/2"
]
}
```

`/books/1`

```json
{
"title": "1984",
"author": "/authors/1"
}
```

`/books/2`

```json
{
"title": "Homage to Catalonia",
"author": "/authors/1"
}
```

`/authors/1`

```json
{
"givenName": "George",
"familyName": "Orwell"
}
```

The `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:

```http
GET /books/ HTTP/2
Preload: "/member/*/author"
```

In addition to `/books`, a Vulcain server will push the `/books/1`, `/books/2` and `/authors/1` resources!

Example in JavaScript:

```javascript
const bookResp = await fetch("/books/1", { headers: { Preload: `"/author"` } });
const bookJSON = await bookResp.json();

// Returns immediately, the resource has been pushed and is already in the push cache
const authorResp = await fetch(bookJSON.author);
// ...
```

[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).

Thanks to [HTTP/2+ multiplexing](https://stackoverflow.com/a/36519379/1352334), pushed responses will be sent in parallel.

When 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!

For 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).
Tip: 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).

When possible, we recommend using [Early Hints](https://tools.ietf.org/html/rfc8297) (the 103 HTTP status code) to push the relations.
Vulcain 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.

### Query Parameter

Alternatively to HTTP headers, the `preload` query parameter can be used:

[tabs]

#### Preload
![Preload Query Schema](schemas/vulcain_doc_preload_query_200.png)

#### Preload + Early Hints
![Preload Query Schema](schemas/vulcain_doc_preload_query_early_hints.png)

#### Server push
![Preload Query Schema](schemas/vulcain_doc_preload_query_server_push.png)

[/tabs]

## Filtering Resources

[tabs]

### Preload
![Filter Schema](schemas/vulcain_doc_filter_200.png)

### Preload + Early Hints
![Filter Schema](schemas/vulcain_doc_filter_early_hints.png)

### Server push
![Filter Schema](schemas/vulcain_doc_filter_server_push.png)

[/tabs]

The `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.

Multiple `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.

Considering the following resources:

`/books/1`

```json
{
"title": "1984",
"genre": "novel",
"author": "/authors/1"
}
```

`/authors/1`

```json
{
"givenName": "George",
"familyName": "Orwell"
}
```

And the following HTTP request:

```http
GET /books/1 HTTP/2
Preload: "/author"
Fields: "/author/familyName", "/genre"
```

A Vulcain server will return a response containing the following JSON document:

```json
{
"genre": "novel",
"author": "/authors/1"
}
```

It will also push the following filtered `/authors/1` resource:

```json
{
"familyName": "Orwell"
}
```

### Query Parameter

Alternatively to HTTP headers, the `fields` query parameter can be used to filter resources:

[tabs]

#### Preload
![Fields Schema](schemas/vulcain_doc_filter_query_200.png)

#### Preload + early hints
![Fields Schema](schemas/vulcain_doc_filter_query_early_hints.png)

#### Server push
![Fields Schema](schemas/vulcain_doc_filter_query_server_push.png)

[/tabs]

## See Also

* [Mapping a non-hypermedia API using OpenAPI](docs/gateway/openapi.md)
* [Cache considerations](docs/cache.md)
* [Using GraphQL with Vulcain](docs/graphql.md#using-graphql-as-query-language-for-vulcain)
* [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)

## License and Copyright

tl;dr:

* proprietary software **can** implement the Vulcain specification
* proprietary software **can** be used behind the Vulcain Gateway Server without having to share their sources
* modifications made to the Vulcain Gateway Server **must** be shared
* alternatively, a commercial license is available for the Vulcain Gateway Server

[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.

The 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**.

For companies not wanting, or not able to use AGPL-3.0 licensed software, commercial licenses are also available. [Contact us for more information](mailto:[email protected]).

## Treeware

This 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.

## Credits

Created by [Kévin Dunglas](https://dunglas.dev). Sponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop).

Some 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.

See also [the prior arts](docs/prior-art.md).