API
The Data Contract CLI can run as a web server that exposes a REST API for data contract testing, linting, exporting, and changelogs. This is useful for integrating data contract checks into other services.
You can try a public demo at api.datacontract.com. Note that the demo endpoint cannot connect to your secured data sources.
Starting the API
The API requires the api extra:
pip install 'datacontract-cli[api]'
Start the server:
datacontract api
| Option | Default | Description |
|---|---|---|
--port | 4242 | Bind the socket to this port. |
--host | 127.0.0.1 | Bind to this host. In Docker, use 0.0.0.0. |
--debug / --no-debug | --no-debug | Enable debug logging. |
You can pass extra keyword arguments through to uvicorn.run(), e.g.:
datacontract api --port 1234 --root_path /datacontract
OpenAPI / Swagger UI
Once running, open the interactive OpenAPI documentation (Swagger UI) at http://localhost:4242. You can execute the commands directly from the UI.
The OpenAPI 3.1 document itself is served at http://localhost:4242/openapi.json and can be fed to
a client generator:
curl -s http://localhost:4242/openapi.json > openapi.json
Test a data contract
POST a data contract as the request body to /test and receive the test results as JSON:
curl -X POST "http://localhost:4242/test?server=production" \
--data-binary @datacontract.yaml
You can also send the YAML inline with -H 'Content-Type: application/yaml'.
Export a data contract
curl -X POST "http://localhost:4242/export?format=sql" \
--data-binary @datacontract.yaml
Changelog between two contracts
POST a JSON body with v1 (before) and v2 (after) as YAML strings. The response is a JSON object with summary and entries:
curl -X POST "http://localhost:4242/changelog" \
-H "Content-Type: application/json" \
-d '{
"v1": "'"$(cat v1.odcs.yaml)"'",
"v2": "'"$(cat v2.odcs.yaml)"'"
}'
Configure server credentials
To connect to a data source, set the required credentials as environment variables before starting the API (see Configuration). For example, for Snowflake:
export DATACONTRACT_SNOWFLAKE_USERNAME=123
export DATACONTRACT_SNOWFLAKE_PASSWORD=
export DATACONTRACT_SNOWFLAKE_WAREHOUSE=
export DATACONTRACT_SNOWFLAKE_ROLE=
Alternatively, POST /test accepts credentials per request via datacontract-* headers (e.g. datacontract-snowflake-password), matched case-insensitively and applied to that request only. This allows one server to test contracts for different tenants without sharing credentials through the process environment. Serve the API over HTTPS when sending credential headers.
Secure the API
Set DATACONTRACT_CLI_API_KEY to a secret value (such as a random UUID) to require authentication. Every endpoint then requires the header x-api-key with the correct key, and answers 401 when it is missing and 403 when it is wrong.
export DATACONTRACT_CLI_API_KEY=<your-secret-key-such-as-a-random-uuid>
Securing the API is highly recommended. Data contract tests may otherwise be subject to SQL injection or leak sensitive information.
Posted contracts are untrusted
A data contract carries SQL and names the hosts to connect to, so a contract that arrives over HTTP is treated as untrusted input, whether or not the API key is set:
- a
quality.type: sqlrule must be a read-only query — DDL, DML,COPY,ATTACHand the like are reported as a failed check instead of being executed; - a credential held in the server's environment is never sent to a host the contract names (see Configuration);
- a
publish_urlmay only point at the Entropy Data platform or the host set viaENTROPY_DATA_HOSTon the server — per-requestentropy-data-hostheaders do not widen this, and other hosts are refused; servers[].type: localis refused, so a caller cannot read the files of the machine running the API;- for a file-based server type (
s3,gcs,azure), the DuckDB connection is confined to the data locations the contract declares.
If the deployment serves its own files on purpose — the data mounted next to the API in the same container, say — allow it explicitly:
export DATACONTRACT_CLI_API_ALLOW_LOCAL_FILES=true
The contract is then still confined to the paths it declares, but a caller chooses those paths, so only turn this on where callers are trusted.
Run as a Docker container
The pre-built image can run the API in any container environment (Docker Compose, Kubernetes, Azure Container Apps, Google Cloud Run, …):
services:
datacontract-api:
image: datacontract/cli:latest
ports:
- "4242:4242"
environment:
- DATACONTRACT_CLI_API_KEY=a079ce4c-af90-45ab-abe5-a8d7697f60d6
command: ["api", "--host", "0.0.0.0"]
See the api command reference.