Skip to main content

Identifiers

Every resource in a broker has an identifier. You choose some of them, such as an entity id or a datasetId, and Andromeda makes up the rest, such as the Notification id on every notification it sends. Both kinds are URIs, both answer to the same length limit, and the ones Andromeda mints all share one shape.

Identifiers you choose​

Anything you can name, you name with an identifier. That covers an entity id, the id of a subscription, registration, Snapshot or EntityMap, a datasetId, and an instanceId you supply on a Temporal API write. Every one of them is an absolute URI, following the URI syntax, with IRIs allowing non-ASCII characters. A relative reference such as Building1 is refused, and so is whitespace anywhere in one, or a character outside the URI grammar.

The familiar urn:ngsi-ld:Building:townhall shape is a convention, not a rule. Any absolute URI names a resource, and an IRI with non-ASCII characters is stored and read back as written.

Length​

Any identifier you choose can be up to 1,024 bytes, counted in UTF-8 as Andromeda stores it. Every identifier is a database index key, which is where the limit comes from. Non-ASCII characters take more than one byte each, so a non-ASCII identifier reaches the limit sooner than its length suggests.

The limit applies to the ids above and to two more things measured as identifiers. One is attribute and entity type names, measured after expansion to their full IRI. The other is the idPattern of a registration's entity selector. Because names are measured after expansion, a short attribute name can go over the limit once your @context expands it under a long @vocab. Identifiers and references has the full list.

A longer identifier is refused with 400 BadRequestData before anything is stored, and the error gives the length and the limit. In a batch, the refusal is reported against that one entity in a 207, and the rest of the batch goes ahead.

A tenant name is the one identifier with its own grammar, [A-Za-z_][A-Za-z0-9_-]*. The specification types a tenant as a String and leaves the spelling to the implementation. It can be at most 1,005 octets, the identifier limit minus the 19 octets of urn:ngsi-ld:Tenant:, because a tenant is also exposed as a resource under that identifier. Tenant names has the details.

Reusing an identifier​

Creating a resource whose id is taken is refused with 409 AlreadyExists, never an overwrite. That holds for entities, subscriptions, Snapshots and clones alike (see AlreadyExists). To change what an identifier names, replace or merge the resource instead of creating it again.

Replace Entity refuses a body whose id differs from the entity in the path, so a write can't silently move one identifier onto another entity's data. An instanceId you supply on a Temporal API write stays the one you chose, because it is how you address that instance afterwards. On a Core API write it is ignored, and Andromeda mints the instance's identifier itself.

Identifiers Andromeda mints​

When you create a subscription, registration or other resource without choosing an id, Andromeda makes one up. You also meet its ids without looking for them, as the Notification id on every notification, the JsonLdContext id in a response's Link header and the instanceId of a temporal attribute. Every one of them looks like urn:ngsi-ld:<Kind>:<id>.

The shape​

urn:ngsi-ld:Subscription:3f2a6c1e-8d4b-4f0a-9b7e-2c5d1a0e6f48

The urn:ngsi-ld: prefix is always written in lowercase. URNs treat urn and the namespace as case-insensitive, so URN:NGSI-LD:... names the same resource. The kind stands in PascalCase and is case-sensitive, and the id is one segment with no colon in it.

ResourceIdentifier
Subscriptionurn:ngsi-ld:Subscription:<uuid>
Subscription Andromeda places on a context sourceurn:ngsi-ld:Subscription:forwarded-<uuid>
Context source registrationurn:ngsi-ld:ContextSourceRegistration:<uuid>
Snapshoturn:ngsi-ld:Snapshot:<uuid>
Snapshot status notificationurn:ngsi-ld:SnapshotNotification:<uuid>
EntityMapurn:ngsi-ld:EntityMap:<uuid>
Notificationurn:ngsi-ld:Notification:<uuid>
Entity type listurn:ngsi-ld:EntityTypeList:<uuid>
Attribute listurn:ngsi-ld:AttributeList:<uuid>
Health checkurn:ngsi-ld:HealthCheck:<uuid>
Component report listurn:ngsi-ld:ComponentReportList:<uuid>
Stored @contexturn:ngsi-ld:JsonLdContext:<uuid>
Tenanturn:ngsi-ld:Tenant:<tenant name>
Temporal attribute instanceurn:ngsi-ld:attribute:instance:<uuid>

The temporal attribute instance is the odd one out, with its lowercase, two-segment shape. It stays that way so that every instanceId already handed out keeps working.

Which UUID​

Most resources get a random UUID (version 4). It carries nothing about when or where the resource was made.

Temporal attribute instances get a time-ordered UUID (version 7). There is one per history row, and time order keeps the index small. You can read roughly when the instance was created from it, but the instance's createdAt says that anyway.

A notification in durable delivery gets a UUID derived from its place in the queue (version 5), computed over the write that made the change, the change's position within that write and the subscription the notification is owed to. Every attempt of that notification carries the same id, so an endpoint can recognise a repeat. In live delivery each notification is sent once, and its id is random. See Retries.

ImplicitlyCreated @context entries get a UUID derived from their content (version 5), computed over the canonical form of the document. Equal documents share one entry. Whitespace, member order and how numbers are spelled don't change the identifier, but array order does. If the identifier is already taken by a different document, Andromeda falls back to a random one. Two different documents are never served under one identifier.