-
Notifications
You must be signed in to change notification settings - Fork 232
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-337: Delegated Content Routing HTTP API #337
Merged
Merged
Changes from 21 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
1d9ec9c
feat: Delegated Routing HTTP API
guseggert 65d178b
changes based on feedback
guseggert 4c024dd
fix some formatting
guseggert 0acdb01
remove unused signature field
guseggert f7b4437
rename to "delegated content routing" and remove IPNS
guseggert 13d695c
use multibase-encoded payload for Provide
guseggert e3e744a
sign the hash of the payload
guseggert 451b1e9
add timestamp type
guseggert 27d23e8
adjust provider record
guseggert a9984a9
specify /ping not ready status code
guseggert fce070f
add note about non-identity-multihashed peer IDs
guseggert fff68c3
rework API and schema based on feedback
guseggert 11f4ca5
formatting fix
guseggert 39c467e
use a JSON string for payload, no reason to base-encode
guseggert 87ff0ac
s/Multiaddrs/Addrs
guseggert 96d55d0
properly distinguish Reframe HTTP transport from Reframe
guseggert 4264a2d
remove dangling status code
guseggert 0f49dcf
add -v1 suffix to filecoin-graphsync protocol name
guseggert 7238e63
Add ID and Addrs fields to filecoin-graphsync-v1 read record
guseggert e823d9e
docs(http-routing): CORS and Web Browsers
lidel 19fff93
Decouple schema from protocol in records
guseggert 1aac44c
ipip-337: apply suggestions from review
lidel acc397b
chore: fix typo
lidel 325ca1e
Reduce the scope of IPIP-337 by excluding write operations
masih 9c47a31
Address lint issues
masih 512bc05
Merge pull request #370 from ipfs/masih/rm_put_deleg_routing_api
lidel 655b1f2
Rename 0000-delegated-routing-http-api.md to 0337-delegated-routing-h…
lidel d343189
Remove pagination and transport & transfer filters
guseggert 573417e
ipip-337: final editorial changes
lidel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# IPIP-337: Delegated Content Routing HTTP API | ||
|
||
- Start Date: 2022-10-18 | ||
- Related Issues: | ||
- https://github.com/ipfs/specs/pull/337 | ||
|
||
## Summary | ||
|
||
This IPIP specifies an HTTP API for delegated content routing. | ||
|
||
## Motivation | ||
|
||
Idiomatic and first-class HTTP support for delegated routing is an important requirement for large content routing providers, | ||
and supporting large content providers is a key strategy for driving down IPFS content routing latency. | ||
These providers must handle high volumes of traffic and support many users, so leveraging industry-standard tools and services | ||
such as HTTP load balancers, CDNs, reverse proxies, etc. is a requirement. | ||
To maximize compatibility with standard tools, IPFS needs an HTTP API specification that uses standard HTTP idioms and payload encoding. | ||
The [Reframe spec](https://github.com/ipfs/specs/blob/main/reframe/REFRAME_PROTOCOL.md) for delegated content routing is an experimental attempt at this, | ||
but it has resulted in a very unidiomatic HTTP API which is difficult to implement and is incompatible with many existing tools. | ||
The cost of a proper redesign, implementation, and maintenance of Reframe and its implementation is too high relative to the urgency of having a delegated content routing HTTP API. | ||
|
||
Note that this does not supplant nor deprecate Reframe. Ideally in the future, Reframe and its implementation would receive the resources needed to map the IDL to idiomatic HTTP, | ||
and implementations of this spec could then be rewritten in the IDL, maintaining backwards compatibility. | ||
|
||
We expect this API to be extended beyond "content routing" in the future, so additional IPIPs may rename this to something more general such as "Delegated Routing HTTP API". | ||
|
||
## Detailed design | ||
|
||
See the [Delegated Content Routing HTTP API spec](../routing/DELEGATED_CONTENT_ROUTING_HTTP.md) included with this IPIP. | ||
|
||
## Design rationale | ||
|
||
To understand the design rationale, it is important to consider the concrete Reframe limitations that we know about: | ||
|
||
- Reframe [method types](../reframe/REFRAME_KNOWN_METHODS.md) using the HTTP transport are encoded inside IPLD-encoded messages | ||
- This prevents URL-based pattern matching on methods, which makes it hard and expensive to do basic HTTP scaling and optimizations: | ||
- Configuring different caching strategies for different methods | ||
- Configuring reverse proxies on a per-method basis | ||
- Routing methods to specific backends | ||
- Method-specific reverse proxy config such as timeouts | ||
- Developer UX is poor as a result, e.g. for CDN caching you must encode the entire request message and pass it as a query parameter | ||
- This was initially done by URL-escaping the raw bytes | ||
- Not possible to consume correctly using standard JavaScript (see [edelweiss#61](https://github.com/ipld/edelweiss/issues/61)) | ||
- Shipped in Kubo 0.16 | ||
- Packing a CID into a struct, encoding it with DAG-CBOR, multibase-encoding that, percent-encoding that, and then passing it in a URL, rather than merely passing the CID in the URL, is needlessly complex from a user's perspective, and has already made it difficult to manually construct requests or interpret logs | ||
- Added complexity of "Cacheable" methods supporting both POSTs and GETs | ||
- The required streaming support and message groups add a lot of implementation complexity, but streaming does not currently work for cachable methods sent over HTTP | ||
- Ex for FindProviders, the response is buffered anyway for ETag calculation | ||
- There are no limits on response sizes nor ways to impose limits and paginate | ||
- This is useful for routers that have highly variable resolution time, to send results as soon as possible, but this is not a use case we are focusing on right now and we can add it later | ||
- The Identify method is not implemented because it is not currently useful | ||
guseggert marked this conversation as resolved.
Show resolved
Hide resolved
guseggert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- This is because Reframe's ambition is to be a generic catch-all bag of methods across protocols, while delegated routing use case only requires a subset of its methods. | ||
- Client and server implementations are difficult to write correctly, because of the non-standard wire formats and conventions | ||
guseggert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Example: [bug reported by implementer](https://github.com/ipld/edelweiss/issues/62), and [another one](https://github.com/ipld/edelweiss/issues/61) | ||
- The Go implementation is [complex](https://github.com/ipfs/go-delegated-routing/blob/main/gen/proto/proto_edelweiss.go) and [brittle](https://github.com/ipfs/go-delegated-routing/blame/main/client/provide.go#L51-L100), and is currently maintained by IPFS Stewards who are already over-committed with other priorities | ||
- Only the HTTP transport has been designed and implemented, so it's unclear if the existing design will work for other transports, and what their use cases and requirements are | ||
guseggert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- This means Reframe can't be trusted to be transport-agnostic until there is at least a second transport implemented (e.g. as a reframe-over-libp2p protocol) | ||
- There's naming confusion around "Reframe, the protocol" and "Reframe, the set of methods" | ||
|
||
So this API proposal makes the following changes: | ||
guseggert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
- The Delegated Content Routing API is defined using HTTP semantics, and can be implemented without introducing Reframe concepts nor IPLD | ||
- There is a clear distinction between the RPC protocol (HTTP) and the API (Deleged Content Routing) | ||
- "Method names" and cache-relevant parameters are pushed into the URL path | ||
- Streaming support is removed, and default response size limits are added along with an optional `pageLimit` parameter for clients to specify response sizes | ||
- We will add streaming support in a subsequent IPIP, but we are trying to minimize the scope of this IPIP to what is immediately useful | ||
- Bodies are encoded using idiomatic JSON, instead of using IPLD codecs, and are compatible with OpenAPI specifications | ||
- The JSON uses human-readable string encodings of common data types | ||
- CIDs are encoded as CIDv1 strings with a multibase prefix (e.g. base32), for consistency with CLIs, browsers, and [gateway URLs](https://docs.ipfs.io/how-to/address-ipfs-on-web/) | ||
- Multiaddrs use the [human-readable format](https://github.com/multiformats/multiaddr#specification) that is used in existing tools and Kubo CLI commands such as `ipfs id` or `ipfs swarm peers` | ||
- Byte array values, such as signatures, are multibase-encoded strings (with an `m` prefix indicating Base64) | ||
- The "Identify" method and "message groups" are not included | ||
- The "GetIPNS" and "PutIPNS" methods are not included | ||
guseggert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### User benefit | ||
|
||
The cost of building and operating content routing services will be much lower, as developers will be able to maximally reuse existing industry-standard tooling. | ||
Users will not need to learn a new RPC protocol and tooling to consume or expose the API. | ||
This will result in more content routing providers, each providing a better experience for users, driving down content routing latency across the IPFS netowrk | ||
lidel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
and increasing data availability. | ||
|
||
### Compatibility | ||
|
||
#### Backwards Compatibility | ||
|
||
IPFS Stewards will implement this API in [go-delegated-routing](https://github.com/ipfs/go-delegated-routing), using breaking changes in a new minor version. | ||
Because the existing Reframe spec can't be safely used in JavaScript and we won't be investing time and resources into changing the wire format implemented in edelweiss to fix it, | ||
the experimental support for Reframe in Kubo will be deprecated in the next release and delegated content routing will subsequently use this HTTP API. | ||
We may decide to re-add Reframe support in the future once these issues have been resolved.- | ||
|
||
#### Forwards Compatibility | ||
|
||
Standard HTTP mechanisms for forward compatibility are used: | ||
- The API is versioned using a version number prefix in the path | ||
- The `Accept` and `Content-Type` headers are used for content type negotiation, allowing for backwards-compatible additions of new MIME types, hypothetically such as: | ||
- `application/cbor` for binary-encoded responses | ||
- `application/x-ndjson` for streamed responses | ||
- `application/octet-stream` if the content router can provide the content/block directly | ||
- New paths+methods can be introduced in a backwards-compatible way | ||
- Parameters can be added using either new query parameters or new fields in the request/response body. | ||
- Provider records are both opaque and versioned to allow evolution of schemas and semantics for the same transfer protocol | ||
|
||
As a proof-of-concept, the tests for the initial implementation of this HTTP API were successfully tested with a libp2p transport using [libp2p/go-libp2p-http](https://github.com/libp2p/go-libp2p-http), demonstrating viability for also using this API over libp2p. | ||
|
||
### Security | ||
|
||
- TODO: cover user privacy | ||
- TODO: parsing best practices: what are limits (e.g., per message / field)? | ||
|
||
### Alternatives | ||
|
||
- Reframe (general-purpose RPC) was evaluated, see "Design rationale" section for rationale why it was not selected. | ||
|
||
### Copyright | ||
|
||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just write the spec within the IDL of the data and define the transport to be this? It seems like it'd be easy enough except for the areas where the divergence of this API runs counter to some of the Reframe goals, which seem worth discussing. For example, I put an alternative that seems to capture some of your major changes below.