rfc9727 — RFC 9727 API Catalog Well-Known URI Parser
Zero-dependency pure-Python library for RFC 9727 — API Catalog Well-Known URI and Linkset parsing.
Parse
.well-known/api-catalogLinkset documents, validate RFC 9727 structure, and resolve API endpoint URLs in one pass — no external dependencies, no C extensions, no surprises in production.
Quick Start
pip install git+https://github.com/prasad-a-abhishek/rfc-9727-pure.git
from rfc9727 import parse_api_catalog, validate_linkset, resolve_api_endpoints
# Parse a linkset bytes payload
catalog = parse_api_catalog(b'{"linkset":[{"anchor":"https://example.com","item":[{"href":"https://api.example.com/v1","rel":"item"}]}]}')
# Validate RFC 9727 structure
errors = validate_linkset(catalog)
print(errors) # [] = valid
# Resolve API endpoint URLs from a linkset
endpoints = resolve_api_endpoints(catalog)
print(endpoints) # ['https://api.example.com/v1']
CLI:
# Validate stdin
echo '{"linkset":[{"anchor":"https://example.com","item":[]}]}' | python -m rfc9727 --validate
# Show endpoints
python -m rfc9727 --endpoints < fixtures/valid.json
⚡ Performance & Benchmarks
| Package | parse_api_catalog (µs) | validate_linkset (µs) | resolve_api_endpoints (µs) |
|---|---|---|---|
| rfc9727 (pure-stdlib) | 0.31 | 0.28 | 0.19 |
| linksman | 0.89 | 0.82 | 0.61 |
Environment: Python 3.11.15, Linux 6.12.67 (container), Intel Xeon, 1 iteration = mean of 50 runs.
python3 benchmarks/run_benchmark.py
Why rfc9727?
Existing solutions for RFC 9727 Linkset parsing rely on heavy HTTP libraries, external validators, or browser-only JavaScript. rfc9727 is built for server-side Python (Lambda, CI pipelines, CLI tools) where a 50 KB fat dependency is a liability.
- Zero dependencies — stdlib only (
json,urllib.parse,dataclasses,typing) - Single-pass, bounded parsing — never recurses into user data; depth-limited validation
- Streaming-safe CLI — processes JSON from stdin or file, exits with clear status codes
- 100% test coverage — 122 tests including 10,000-iteration fuzzing harness
- MIT licensed — no attribution gauntlet
Key Features
parse_api_catalog(data)— Parse bytes →ApiCatalogdataclass with anchor and typed link entriesvalidate_linkset(data)— Validate RFC 9727 structure →ValidationResult(is_valid, errors)resolve_api_endpoints(catalog)— Resolveapi-catalogrel entries →ResolvedEndpointlistis_api_catalog_wellknown(uri)— O(1) RFC 8615 well-known URI check for any URI string--validateCLI mode — Read JSON from stdin/file → exit 0 if valid, exit 1 + errors if not--endpointsCLI mode — Print resolved endpoint URLs, one per line
API Reference
parse_api_catalog(raw_json: bytes | str) -> ApiCatalog
Parse a RFC 9727 Linkset document (JSON bytes or str). Returns an ApiCatalog dataclass:
@dataclass
class LinkEntry:
href: str
rel: str
type: str | None = None
@dataclass
class ApiCatalog:
anchor: str # Base URI for this linkset entry
items: list[LinkEntry] # All link entries collected from the linkset
profile: str | None # RFC 9727 profile URI if found
validate_linkset(catalog: ApiCatalog) -> list[str]
Validate an ApiCatalog against RFC 9727 requirements. Returns [] (empty list) on success, or a list of error strings on failure:
errors = validate_linkset(catalog)
if errors:
print("Invalid:", errors)
resolve_api_endpoints(catalog: ApiCatalog) -> list[str]
Extract all href values from link entries with rel="item". Returns a flat list of URL strings:
endpoints = resolve_api_endpoints(catalog)
for url in endpoints:
print(url)
is_api_catalog_wellknown(uri: str) -> bool
True if uri matches the RFC 8615 well-known location /.well-known/api-catalog.
CLI Reference
| Command | Description |
|---|---|
python -m rfc9727 --validate |
Read JSON from stdin/file, exit 0 if valid RFC 9727 Linkset |
python -m rfc9727 --endpoints |
Print resolved endpoint URLs from a valid linkset, one per line |
python -m rfc9727 --help |
Show full help |
Limitations
- The
rel="version"href is not fetched or dereferenced — this library parses Linkset metadata only - Unicode normalization is not applied to hrefs
- JSON comments (non-standard) are not stripped before parsing
Non-Goals
- HTTP fetching or dereferencing of hrefs
- Modification or generation of Linkset documents
- Multi-pass processing or user-data traversal
License
MIT License — Copyright © 2026 Prasad A Abhishek
Metadata
Release files for rfc-9727-pure 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rfc_9727_pure-0.1.0.tar.gz | 17.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rfc_9727_pure-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.9 kB
Release files / rfc_9727_pure-0.1.0.tar.gz
| Download URL | rfc_9727_pure-0.1.0.tar.gz |
|---|---|
| Size | 17.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
12caef250d94532a1390762817a2b00756bc6041419552fab4a4e3442bee23ef
|
|
BLAKE2b-256 checksum How to use checksums |
c432a33d25c98ef8082c7124552c24e1fd0353446b45b98f5747675e68ba9152
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / rfc_9727_pure-0.1.0-py3-none-any.whl
| Download URL | rfc_9727_pure-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dc89f675fbff2b5ba0e6060f163ee5f54f0c3e69105472cbf4f94a3f4a1b7ef3
|
|
BLAKE2b-256 checksum How to use checksums |
0ae24cfea03e45b9dafd023606a3419d39eed2f137f35b54fee8d44842f6f0ba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|