Skip to content

Conventions

Every OURS resource is a JSON object that follows the same few conventions. They are FHIR’s conventions, reused so that existing tooling and existing instincts carry over.

Field Type
resourceType string, required Ontology, Model or Vocabulary.
id string, required Short identifier, unique within the ontology.
url URL, required The resource’s identity. See below.
version string, required The publisher’s own version, in the publisher’s own scheme.
publisher string, optional Who publishes it. Required on an Ontology.
name string, optional Human-readable name. Required on a Model and a Vocabulary.
description string, optional What it means, in prose, for a human reader.

A resource’s url is how everything else refers to it, and a consumer treats two resources with the same url as the same thing. Three consequences follow.

Serve the resource at the URL it claims. A document fetched from one address that identifies itself as another gives a consumer two candidate identities and no rule for choosing.

Do not reuse a url for a different resource. Changing what lives at an address is not a version bump, it is a substitution, and nothing pointing at the old meaning will notice.

Do not move one casually. Every mapsTo, every $ref, and every consumer’s stored reference points at the URL, so moving a resource breaks them the way renaming a published API endpoint does.

version is a string and the format does not impose a scheme. Semantic versioning is a reasonable default and a date is a reasonable alternative for a vocabulary that tracks an external release, as ISO 4217 does.

The version describes the resource, not the ontology as a whole. A model may sit at 2.1.0 inside an ontology at 1.0.0; there is no requirement that they move together.

A document is what a consumer gets from one fetch. It is either a single resource or a Bundle collecting several:

{
"resourceType": "Bundle",
"type": "collection",
"entry": [
{
"fullUrl": "https://ours.example.org/models/person.json",
"resource": { "resourceType": "Model", "id": "person" }
}
]
}
Field Type
resourceType string, required Always Bundle.
type string, required Always collection. OURS uses no other bundle type.
entry array, required May be empty.
entry[].fullUrl URL, required The entry’s url, repeated where a reader can see it without parsing the resource.
entry[].resource object, required An Ontology, Model or Vocabulary.

Both packagings are correct. Serving one bundle of every model is one fetch and one cache entry; serving a file per model lets a consumer take only what it needs. Readers accept either, so this is a publishing decision rather than something a consumer has to be told in advance.

An Ontology requires all three of models, vocabularies and mappings, and a publisher who has none of something serves an empty collection rather than dropping the pointer:

{ "resourceType": "Bundle", "type": "collection", "entry": [] }

An absent URL cannot be told apart from one that has not been published yet, so a consumer meeting one has to decide whether to keep looking, ask someone, or give up. An empty bundle at a live URL is a definite answer, and the point of the format is that nobody should have to ask.

The per-alignment mapping field on mapsTo stays optional, and the asymmetry is deliberate. There the alignment is already in front of the reader, so the field’s absence says “no executable map for this one” without ambiguity. It is only at the ontology root, where nothing else is present to speak, that silence cannot be read.

  • Send Content-Type: application/json.
  • Send Access-Control-Allow-Origin, or browser-based consumers cannot read the ontology at all.
  • Set cache headers you can live with. A long max-age on a document you revise will serve the old one long after you have fixed it.
  • Keep the URLs stable, for the reasons above.