Identifiers¶
Every DFC object has a stable identity that travels with it across systems. This page explains what the connectors accept, what they preserve, and what they refuse to do.
The identifier is yours, not the SDK's¶
semanticId is the first argument to every factory. The connectors never
generate one, never rewrite one, and never require a particular form:
const org = c.createOrganization("https://example.com/org/1", { name: "Acme" });
const price = c.createPrice("urn:uuid:8f14e45f", { value: 42.5 });
That last one matters: you are not locked into HTTP URIs because the field is
called an id. Anything you can write in a JSON-LD @id works.
What is accepted¶
Verified against the TypeScript connector, identical in the other two:
| Form | Example | Result |
|---|---|---|
| Absolute IRI | https://example.com/org/1 |
preserved verbatim |
| URN | urn:uuid:8f14e45f |
preserved verbatim |
| CURIE | example:org2 |
preserved verbatim |
| Relative / opaque | org3 |
preserved verbatim |
| Blank node | _:b1 |
preserved verbatim |
No validation is performed. The connectors will not tell you that org3
is not a resolvable IRI, because whether it should be resolvable is a
property of your data graph, not of the identifier alone. If you need that
check, do it in your own layer — see validation for why the
connectors do not.
The one place a blank node is worth understanding: _:b1 is scoped to the
document that contains it and has no meaning outside it. It is appropriate
for a node that exists only to be referenced once. Anything that must be
looked up later wants an IRI.
What is preserved¶
The identifier is round-tripped exactly. Import reads @id; export writes it
back:
This is the reason the connectors take the identity as a separate argument rather than inferring one from the content. A content-addressed identifier would change every time a label changed, which breaks every reference to the object everywhere. See relationships for how references survive that.
Identifier versus blank node in graphs¶
When you export several objects at once, the result is a @graph. Each
object keeps its own @id, and references between them are written as
@id values — the document is internally consistent either way:
const doc = JSON.parse(await c.export(org, carrots));
// doc["@graph"] entries carry @id; dfc-b:supplies holds the other @id
Exporting a single object produces a bare node with no @graph wrapper.
Import accepts both, and always returns an array — see the
JSON-LD round trip tutorial.
Watch out¶
- The identity is not a key. Re-exporting a document whose two objects
share an
@idproduces two entries with the same@id. The connectors will not deduplicate or complain. - A renamed object breaks its references. Nothing in a DFC document links
back to the object, so renaming an
@idsilently orphans every reference to it. There is no referential-integrity check. - Blank nodes are not stable across exports. Two exports of the same
in-memory graph will use the same
_:b1only because you passed the same string. Let the connectors manage blank nodes and you have none to manage; there is no blank-node allocator.