Skip to content

Identify a label source’s display field by role, not by the name label #692

Description

@ddeboer

A label source must declare its display field under the literal name label (labelFieldOf, schema.js:266):

export function labelFieldOf(searchType) {
    const field = fieldNamed(searchType, 'label');
    return field !== undefined && field.kind === 'text' &&
        field.output === true && field.searchable !== undefined ? field : undefined;
}

The name is the only thing identifying the role, and that leaks into the API. In a SCHEMA-AP-NDE schema every label source reads schema:name, so six root types declare an identical field renamed to label purely to satisfy the contract:

{ name: 'label', kind: 'text', path: schemaProperty('name'), locales: LOCALES,
  required: true, output: true, searchable: { weight: 5 }, sortable: true }

An API consumer then sees the same triple under two keys depending on which door they came in – persons { label } from the collection, creator { name } through the reference (PersonReference { id, name }) – with nothing in the response indicating they are the same property. Reported downstream by an implementor who expected name, because name is what the profile they were reading calls it.

Proposal

Identify the label field by role, not by name: an additive capability opt-in alongside output/sortable, e.g. isLabel: true. It restricts nothing – the field keeps whatever capabilities it declares – it only states that this type serves its display label from this field. Exactly one per label source, enforced by validation.

// SCHEMA-AP-NDE
{ name: 'name',      kind: 'text', path: schemaProperty('name'),      isLabel: true,}

// a SKOS-based profile
{ name: 'prefLabel', kind: 'text', path: skosProperty('prefLabel'),   isLabel: true,}
  • labelFieldOf finds the flagged field instead of the named one.
  • Validation becomes: a type named as a labelSource declares exactly one flagged text field, output and searchable.
  • labelSource: 'Person' is unchanged at every reference site – the field name stays a property of the referenced type, declared once, so it cannot drift between references.
  • The generated reference type's key follows the label source's field name (PersonReference { id, prefLabel }), so a concept has one name across both surfaces.

Why not just rename the contract to name

That moves the presumption rather than removing it: label presumes SKOS/RDFS, name presumes schema.org. A profile-neutral layer should decline to pick, and let each schema surface its own vocabulary.

Also fixes

A type with a field legitimately named label that is not meant as a display label currently becomes a valid label source by accident.

Migration

Breaking for the generated GraphQL surface where a reference key changes. In this repo the six declarations rename labelname and add the flag.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions