coreapi
A Python client library for interacting with hypermedia and schema-described APIs across CoreJSON, OpenAPI, JSON Hyper-Schema, and HAL.
Repository Health
Technical Analysis
coreapi is a Python client library, written by Tom Christie (creator of Django REST Framework and httpx), for interacting with APIs that are described by a machine-readable hypermedia or schema document rather than a hardcoded set of endpoint URLs. A client fetches a document — in CoreJSON, OpenAPI (“Swagger”), JSON Hyper-Schema, or HAL — and the library exposes its advertised operations as navigable Link objects nested inside an immutable Document tree.
Instead of generating fixed methods for each endpoint, callers index into the document (document['section']['action']) and invoke client.action(document, keys, params={...}), with parameters validated against the link’s declared fields before any request is sent. A pluggable codec and transport system, discovered via setuptools entry points, lets the format-negotiation and request layers be extended by third parties without touching the core client.
What You Get
- A
Clientclass that fetches a schema/hypermedia document and exposes its declared actions as callable links - A pluggable codec system with built-in support for CoreJSON, OpenAPI (“Swagger”), JSON Hyper-Schema, and HAL
- An immutable
Document/Object/Array/Linkdata model that can be indexed and traversed like nested Python data - Parameter validation against a link’s declared required/optional fields before a request is sent
- A pluggable transport layer, with a
requests-basedHTTPTransportshipped by default, supporting custom auth and sessions
Common Use Cases
- Talking to any Core API/OpenAPI-schema-driven service without hand-writing or generating a dedicated SDK
- Interactively exploring an API’s available actions and parameters from a Python shell or notebook
- Powering schema/codec-based tooling such as Django REST Framework’s browsable API and the coreapi CLI
- Writing integration scripts against hypermedia APIs (HAL, JSON Hyper-Schema) with one consistent client interface
Under The Hood
Architecture
coreapi is organized as a small orchestrating Client (coreapi/client.py) around three pluggable layers: an immutable document model (coreapi/document.py) representing Document, Object, Array, Link, and Error nodes; a codec registry (coreapi/codecs/) that encodes and decodes those nodes to and from wire formats; and a transport registry (coreapi/transports/) that performs the actual network call. Client.get() and Client.action() both resolve to transport.transition(link, decoders, ...), which negotiates content type against the installed codecs and returns a new immutable Document. Codecs and transports are discovered dynamically via setuptools entry points (coreapi.codecs, coreapi.transports), so third parties can register additional formats or protocols without modifying the core package — a plugin-registry pattern that keeps the client itself format-agnostic. Because every codec and transport must agree on the same Document/Link/Field shapes, changing that core data model would ripple through every codec and the transport layer at once.
Tech Stack
The library targets Python 2.7 and 3.3+ (with a compat.py shim module and from __future__ import unicode_literals throughout), reflecting its 2015-era origin. Runtime dependencies are requests (the default HTTP transport), coreschema (field/type definitions for link parameters), itypes (immutable object and list wrappers used by the document model), and uritemplate (RFC 6570 URI template expansion for parameterized links). It’s packaged with a classic setuptools setup.py using entry points for plugin discovery, documented via mkdocs (docs/api-guide/*.md), and was CI-tested on Travis (.travis.yml, tox.ini).
Code Quality
The tests/ directory covers codecs, the document model, exceptions, transports, and end-to-end transitions (test_codecs.py, test_document.py, test_transitions.py, test_transport.py, test_integration.py, test_utils.py) via pytest, with a runtests script wiring in flake8 linting and coverage. Errors are surfaced through a dedicated exceptions.py hierarchy (ParameterError, LinkLookupError, NoCodecAvailable, NetworkError) rather than being swallowed, and naming is consistently snake_case with docstrings on public classes. There are no type hints or static type checking — unsurprising for Python-2-compatible code from this era — and the repository has seen no commits since 2019, so its CI configuration (Travis) is effectively dead.
API Design
coreapi’s defining choice is treating the API itself as introspectable data: rather than generating a fixed method per endpoint, it exposes one generic indexing interface (document['section']['action']) plus a single client.action(document, keys, params={...}) call, following a hypermedia/HATEOAS philosophy where the client never hardcodes URLs — it navigates purely through whatever the schema document advertises. Getting started requires only Client().get(url), but the indexing-based call style trades away the autocomplete and type safety of a hand-generated SDK, and it depends entirely on the server publishing a schema in a format coreapi understands. The ideas here fed into Django REST Framework’s schema generation, from the same author (Tom Christie), though the broader API tooling ecosystem has since largely converged on OpenAPI-based code generation instead of runtime hypermedia navigation.