Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPIP-0388: Routing HTTP API Support for Querying Multiple Routers #388

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions src/ipips/ipip-0388.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
title: "IPIP-0388: Routing V1 Support for Querying Multiple Routers"
date: 2023-03-20
ipip: proposal
editors:
- name: Adin Schmahmann
github: aschmahmann
affiliation:
name: Protocol Labs
url: https://protocol.ai/
- name: Marcin Rataj
github: lidel
url: https://lidel.org/
affiliation:
name: Protocol Labs
url: https://protocol.ai/
relatedIssues:
- https://github.com/ipfs-shipyard/someguy/issues/12
- https://github.com/ipfs-shipyard/someguy/issues/13
- https://github.com/ipfs/bifrost-gateway/issues/151
order: 388
tags: ['ipips']
---

## Summary

Adding opt-in support for querying individual routers to a single Routing v1 HTTP endpoint,
and discovering available routers via HTTP GET.

## Motivation

At the moment there is no way for a Routing v1 client to ask for a specific routing backend to be used nor for a Routing v1 endpoint to signal what routing backends they support. When Routing v1 is used as a proxy for one or more routing systems (e.g. IPFS Public DHT, IPNI, mainlineDHT, ...) clients may want to be able to judge a given endpoint's suitability to be a proxy for that routing system.

For instance if all-the-routers.alice.tld is very good at proxying IPNI requests but bad at proxying IPFS Public DHT requests, but dht-proxy.bob.tld is good at proxying IPFS Public DHT requests. In this scenario clients wanting good responses would have to ask both Alice and Bob to do DHT lookups for them even though Alice's DHT lookups are unneccessary because Bob is doing them. Similarly, clients could evaluate the best endpoint to request responses from since they can now do comparisons between largely equivalent routing systems. Additionally, this allows clients to discover the data sources behind Routing v1 endpoints without as much out of band information.

IPFS Ecosystem is also lacking a HTTP-native way for discovering available HTTP routers.

## Detailed design

The proposal is to:
1. Add a `?routing=<list-of-routers>` optional parameter to `GET /routing/v1/providers/{CID}` (and other lookup endpoints) that indicates which routing systems to use
2. Add an `GET /routing/v1/routers` endpoint which when queried may respond with a results that follow the `router` schema.

Details in :cite[http-routing-v1].

## Design rationale

We want to create opt-in way for a client to enumerate supported backends, and make a query using a specific backend.
We do not want to change any default behavior, or create yet another HTTP API only for the purpose of discovering other routers.

A real world example, cid.contact HTTP service, effectively has two backend routers: (1) IPNI and (2) [CaskaDHT](https://github.com/ipni/caskadht) proxy.
Rhea/Saturn (Lassie) queries both backends at the same time via cid.contact-specific API queries: `https://cid.contact/cid/{cid}?cascade=ipfs-dht`.

This IPIP aims to make the same possible via vendor-agnostic `/routing/v1/providers/{cid}?routers=all` and create more flexible API for HTTP clients like ipfs-chromium or Brave mobile.

We allow enumeration of available router backends via plain HTTP `GET /routing/v1/routers` for better DX/UX and interop with HTTP tools.

### User benefit

End users will be able to query endpoints that provide proxies for multiple routing systems (e.g. `cid.contact/routing/v1`) and get back DHT, IPNI or both depending on what they need.

For users that are running a DHT client locally they can dynamically evaluate if cid.contact's DHT proxy is either good enough that they can conserve their local resources by reducing how they use their client. Similarly, if they discover that their local DHT results are better than cid.contact's DHT proxy then they can ease the burden on cid.contact by only requesting IPNI results and doing the DHT lookups themselves.

### Compatibility

This should not effect existing clients or servers.

The default behavior when `?routers` is not passed is left unspecified, this IPIP is limited to opt-in behavior.

### Security

Mostly not applicable. However, clients should not expect proxies to give 1:1 mappings with the underlying systems if they are too expensive and should consider that when evaluating the performance of individual endpoints.

### Alternatives

- Having clients fetch from multiple sources which may have overlapping data -> lots of work on servers and extra processing work for clients
- Having clients fetch from a single source with the best data -> is not friendly to the introduction of new services and may result in less data being retrieved
- Having servers restrict to one endpoint per router (e.g. dht.alice.tld and ipni.alice.tld or alice.tld/dht/routing/v1 and alice.tld/ipni/routing/v1) -> also doable, but discoverability of new router types would require other semantics (e.g. an OPTIONS request to alice.tld/routing/v1)
- Having `OPTIONS` instead of `/routing/v1/routers` -> also good, but given that we ended up with more metadata per router, cramming that into HTTP headers would not be the best UX, nor it would work in web browser.
- Having `OPTIONS` on `/routing/v1/providers/{CID}` in the event the CID tells you some information about which providers to use (e.g. for non-BitTorrent codecs don't use mainline DHT) -> also doable. Unclear if this would be useful in practice since sometimes the codec information will get lost (e.g. replaced with the raw/0x55 codec).

### Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
89 changes: 87 additions & 2 deletions src/routing/http-routing-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,31 @@ maturity: reliable
editors:
- name: Gus Eggert
github: guseggert
affiliation:
name: Protocol Labs
url: https://protocol.ai/
- name: Masih H. Derkani
github: masih
affiliation:
name: Protocol Labs
url: https://protocol.ai/
- name: Henrique Dias
url: https://hacdias.com/
github: hacdias
affiliation:
name: Protocol Labs
url: https://protocol.ai/
- name: Adin Schmahmann
github: aschmahmann
affiliation:
name: Protocol Labs
url: https://protocol.ai/
- name: Marcin Rataj
github: lidel
url: https://lidel.org/
affiliation:
name: Protocol Labs
url: https://protocol.ai/
xref:
- ipns-record
order: 0
Expand Down Expand Up @@ -78,6 +98,20 @@ Specifications for some transfer protocols are provided in the "Transfer Protoco

- `cid` is the [CID](https://github.com/multiformats/cid) to fetch provider records for.

#### Query Parameters

##### `routers` (request query parameter)

An optional comma-separated list of routers that should be consulted for responses.

If no `routers` are provided the server SHOULD decide which ones to use as an implicit default.

The specification imposes no constraints on the order by which the results are returned.

Clients SHOULD be able to explicitly select all available backend routers via opt-in `?routers=all` query prameter.

Servers SHOULD allow clients to determine the list of available routers via `GET /routing/v1/routers`.

#### Response Status Codes

- `200` (OK): the response body contains 0 or more records.
Expand All @@ -102,6 +136,36 @@ Response limit: 100 providers

Each object in the `Providers` list is a *read provider record*.

## Routers API

### `GET /routing/v1/routers`

#### Response Status Codes

- `200` (OK): the response body contains 0 or more records.
- `404` (Not Found): returned if backend enumeration is not possible

#### Response Body

```json
{
"Routers": [
{
"Schema": "router",
"Name": "<router_name>",
...
},
...
]
}
```

Response limit: 100 routers

Each `Name` can be used in explicit `?routers=name1,name2` queries.

Additional metadata per router SHOULD be included in other fields defined by `router` schema.

## IPNS API

### `GET /routing/v1/ipns/{name}`
Expand Down Expand Up @@ -199,9 +263,30 @@ Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
```

## Known Transfer Protocols
## Known Schemas

This section contains a non-exhaustive list of known schemas (by name) that may be supported by clients and servers.

### Router

- Schema: `router`
- Specification: see `GET /routing/v1/routers` above

```json
{
"Schema": "router",
"Name": "example",
"Default": false, // is it used when no ?routers is not passed
"RoutingType": ["providers", "ipns", "peers"], // where can this router be used
"Description": "A human-readable description of this router.",
"Addrs": ["/ip4/..."] // optional URLs or Multiddrs of the upstream router
}
```

The `Name` is an opaque string but it MUST never be `all`, as it is reserved
keywork for enabling all backend routers via `?routers=all`.

This section contains a non-exhaustive list of known transfer protocols (by name) that may be supported by clients and servers.
There is no canonical set of router names, each `/routing/v1` implementation SHOULD come up with meaningful names and descriptions.

### Bitswap

Expand Down