API contracts & versioning
Purpose: Keep AEM stable as both an API consumer and an API provider while upstreams and consumers evolve.
Who this page is for
| Audience | Why it matters to you |
|---|---|
| Backend engineers | Both sides of every contract |
| Tech leads | Change coordination |
AEM as consumer
- Pin to explicit upstream API versions (URL or header versioning — whatever the provider offers); "latest" is an outage subscription.
- Own a client model: map upstream JSON → your domain classes at the integration boundary; the rest of the codebase never sees upstream field names. Upstream renames then cost one mapper change.
- Tolerant reader: ignore unknown fields, require only what you use, defaults for optionals — upstream *additive* changes must be non-events.
- Contract tests in CI: recorded/sample responses per version verified against the mapper; plus a stage smoke against the real endpoint (pipeline gates).
- Deprecation intake: subscribe to provider change channels; the integration register tracks sunset dates.
AEM as provider
Your exported JSON (JSON delivery) and CF APIs are contracts consumed by apps you don't control:
| Rule | Mechanism |
|---|---|
| Additive-only evolution | Model/exporter review gate; new fields optional |
| Breaking changes = new version | Selector-versioned (.model.v2.json) or parallel model; old version sunset with notice |
| Published samples per version | Checked-in JSON fixtures — they double as regression tests |
| Know your consumers | Consumer register (who calls what) — you cannot deprecate what you cannot enumerate |
| Stability signals | Release notes flag JSON-shape changes (versioning) |
The coordination artefact
For each contract: a one-page spec (fields, types, nullability, examples, version, owner, consumers) in version control. OpenAPI where the consumer count justifies it; a disciplined markdown table where it doesn't. The artefact's existence matters more than its format — it is what turns "the app broke" into a 10-minute diff.