# Rust API
The `odcs` crate provides parsing, validation, and inspection for ODCS v3.1.0 documents. Generated API docs: [docs.rs/odcs](https://docs.rs/odcs).
## Installation
Add to `Cargo.toml`:
```toml
[dependencies]
odcs = "0.9"
```
For library-only use (no CLI binary):
```toml
odcs = { version = "0.9", default-features = false }
```
See [installation.md](installation.md) for `cargo install` and from-source setup.
For choosing between `parse`, `into_contract`, and `parse_strict`, see [API decision guide](api-guide.md).
## Quick start
```rust
use odcs::{parse, validate, DocumentFormat};
let yaml = br#"
version: "1.0.0"
apiVersion: "v3.1.0"
kind: "DataContract"
id: "hello-contract"
status: "draft"
schema:
- name: customers
properties:
- name: customer_id
logicalType: string
required: true
"#;
let result = parse(yaml, DocumentFormat::Yaml);
let contract = result.into_contract().expect("valid contract");
```
`into_contract()` parses and validates in one step. For other patterns see [API decision guide](api-guide.md).
## Parsing
### `parse(content, format)`
Parse from bytes. Returns a `ParseResult` with optional `contract` and parse-time `report`.
```rust
use odcs::{parse, DocumentFormat};
let result = parse(yaml_bytes, DocumentFormat::Yaml);
```
### `parse_file(path)`
Parse from a file path. Infers format from `.yaml`, `.yml`, or `.json` extension. Returns `miette::Result<ParseResult>` — add `miette` to your `Cargo.toml` if you use `?`, or read the file with `std::fs` and call `parse()`. See [API decision guide — File I/O](api-guide.md#file-io-and-miette).
```rust
use odcs::parse_file;
let result = parse_file("contract.yaml")?;
```
### `DataContract` helpers
```rust
use odcs::DataContract;
let result = DataContract::from_yaml(yaml_text);
let result = DataContract::from_json(json_text);
let result = DataContract::from_file("contract.yaml")?;
```
## ParseResult
```rust
let result = parse(content, DocumentFormat::Yaml);
// Contract only when parse and validation both succeed
let contract = result.into_contract()?;
// Validate without consuming (merges parse + validation diagnostics)
let report = result.validate();
// Parse-time diagnostics only
let parse_ok = result.report.is_valid();
```
`into_contract()` runs validation and returns `Err(DiagnosticReport)` when parse or validation fails.
## Validation
### `validate(contract)`
Validate a parsed `DataContract`. Since 0.4.0, default validation includes pinned ODCS v3.1.0 JSON Schema checks.
```rust
use odcs::validate;
let report = validate(&contract);
if !report.is_valid() {
for d in &report.diagnostics {
eprintln!("{}: {}", d.id, d.message);
}
}
```
### `parse_and_validate(content, format)`
Parse and validate in one step. Returns a `ValidationReport`.
```rust
use odcs::{parse_and_validate, DocumentFormat};
let report = parse_and_validate(yaml_bytes, DocumentFormat::Yaml);
assert!(report.is_valid());
```
### `parse_strict(content, format)`
Parse and validate shortcut. Returns `Result<DataContract, DiagnosticReport>`. Unknown fields are rejected during serde deserialization (not a separate strict mode).
```rust
use odcs::{parse_strict, DocumentFormat};
let contract = parse_strict(yaml_bytes, DocumentFormat::Yaml)?;
```
## Inspection
```rust
use odcs::inspect_contract;
let summary = inspect_contract(&contract);
```
Use the CLI `odcs inspect` for JSON output fields (`id`, `schemaCount`, `qualityCount`, etc.).
## Key types
| `DataContract` | Root canonical object model |
| `ParseResult` | `{ contract, report }` from parsing |
| `DiagnosticReport` / `ValidationReport` | Collection of `Diagnostic` records |
| `Diagnostic` | Error/warning with `id`, `severity`, `message`, `object_ref`, … |
| `DocumentFormat` | `Yaml` or `Json` |
## Constants and codes
```rust
use odcs::UPSTREAM_SPEC_VERSION; // "3.1.0"
use odcs::codes; // odcs::codes::INVALID_KIND, etc.
```
See [diagnostics.md](diagnostics.md) for the full code table.
## Features
| `cli` | yes | `odcs` binary |
| `python` | no | PyO3 bindings (used by maturin) |
## Error handling pattern
```rust
use odcs::{parse_file, DocumentFormat};
fn main() {
let result = match parse_file("contract.yaml") {
Ok(r) => r,
Err(e) => {
eprintln!("{e}");
std::process::exit(2);
}
};
match result.into_contract() {
Ok(_contract) => {}
Err(report) => {
for d in &report.diagnostics {
eprintln!("{}: {}", d.id, d.message);
}
std::process::exit(1);
}
}
}
```
Using `miette` for fancy errors is optional — `parse_file` returns `miette::Result` because `miette` is a crate dependency. Add `miette = { version = "7", features = ["fancy"] }` if you use `fn main() -> miette::Result<()>`.
## Limits
- Maximum document size: 16 MiB (`MAX_PARSE_BYTES`)
- Supported formats: YAML (`.yaml`, `.yml`) and JSON (`.json`)
## Multi-document validation
Load a primary contract with explicit dependencies, include directories, or a registry root:
```rust
use odcs::{load_set_with_registry, validate_set};
use std::path::Path;
let set = load_set_with_registry(
Path::new("consumer.yaml"),
&[Path::new("provider.yaml").to_path_buf()],
&[],
None,
)?;
let report = validate_set(&set);
assert!(report.is_valid());
```
With a local registry:
```rust
use odcs::{load_registry, load_set_with_registry, validate_set};
use std::path::Path;
let registry = load_registry(Path::new("./contracts/"))?;
let set = load_set_with_registry(
Path::new("consumer.yaml"),
&[],
&[],
Some(®istry),
)?;
let report = validate_set(&set);
```
Convenience helpers: `load_set`, `parse_and_validate_set`, `parse_and_validate_set_with_registry`. See [Local registry](registry.md).
## Compatibility diff
```rust
use odcs::{diff, parse_file};
let old = parse_file("old.yaml")?.into_contract()?;
let new = parse_file("new.yaml")?.into_contract()?;
let report = diff(&old, &new);
if report.has_breaking {
for change in &report.changes {
eprintln!("{}: {}", change.path, change.message);
}
}
```
See [Compatibility analysis](compatibility.md).
## Python equivalent
See [python.md](python.md). Maintainer-oriented API notes: [../implementation/public-api.md](../implementation/public-api.md).