Skip to main content

Understanding Content Type Schema

This reference explains how your Java content type classes map to GraphQL schema types in the GCA. Understanding this mapping is essential for crafting effective queries and mutations: it covers the transformation from Java field definitions to GraphQL field types, how relationships and embedded objects are represented, what metadata fields the GCA includes automatically, and the schema directives that carry Brightspot-specific metadata.

Which types end up in the schema

The schema starts from your configured entry types (readonlyEntryClass / mutableEntryClass) and crawls outward: every record-typed field's possible types are visited until the full reachable graph is covered. A configured supertype automatically pulls in its concrete subtypes—configuring CreativeWork exposes Article, Gallery, and Video if they extend it.

Three settings shape the crawl:

  • referenceTypeFilter(...) — controls which types may be resolved through reference fields. By default, only entry types are resolvable as references; everything else returns a restricted reference (see Restricted references). Embedded types are always accessible through their parent.
  • fieldFilter(...) — include/exclude individual fields from the schema.
  • richTextElementTypeFilter(...) — controls which rich-text element types are included.

Type naming

A type's GraphQL name is its Java simple class name (Article). On conflict, the package name is used to disambiguate (Article_bar), with entry types getting naming priority. You can take full control with objectTypeTypeNameFunction(...). Every generated type carries a @bsp_type(internalName: ...) directive linking it back to the Dari ObjectType, so consumers never need to guess.

Anatomy of a generated type

A content type's fields come in three groups—globals, declared fields, and modifications:

1
type Article implements Record {
2
# Globals — present on every record
3
_id: ID
4
_label: String
5
_globals: Globals!
6
_urls: URLs!
7
8
# Declared fields — from the Java class (and superclasses)
9
headline: String
10
body: String
11
tags: [String]
12
author: Author
13
leadImage: StorageItem
14
15
# Modifications — one field per modified type
16
TaggableMod: TaggableMod
17
}

Global fields

FieldDescription
_idThe record's UUID.
_labelThe record's display label, as shown in the CMS.
_globalsContainer for global modifications—data attached to all records (e.g. SEO fields). Each global modification appears as a field on the Globals type.
_urlsThe record's URL data—permalink and paths—when URL support applies.
_previewA StorageItem for the record's preview image. Only on types whose Java class declares @PreviewField, expressed via the RecordPreview interface.
_rawThe raw state as JSON. Only present with allowRawStateAccess()bypasses all field filters, so enable with care.

Every record type implements the Record interface, which declares the global fields—handy for writing fragments that work across all types.

Declared fields

Java fields map to GraphQL fields using the Java field name. Getter methods registered as ObjectMethods (e.g. annotated @Ignored(false)) also become fields, named by stripping the get/is/has prefix and lower-casing (getFoo()foo).

When a field and its getter would produce the same name, the GCA merges them into one field. At runtime the merged field returns the getter's value by default—after all, the getter may apply business logic. To read the raw stored value instead, use the @bsp_raw query directive:

1
{
2
Query {
3
Records(from: {type: Article}) {
4
items @bsp_raw(if: true) { # raw values for all fields below...
5
... on Article {
6
headline
7
body @bsp_raw(if: false) # ...except this one
8
}
9
}
10
}
11
}
12
}

Field-level documentation flows through automatically: Javadoc comments on your Java fields become GraphQL descriptions, visible in the Explorer and SDL.

Modifications

Dari Modifications appear as one field per modified type, named <ModifiedType>Mod (e.g. TaggableMod: TaggableMod). If exactly one modification targets the type, its fields are presented on that type; with multiple modifications, the Mod type contains one field per modification class.

If you prefer modification fields without the extra nesting level when there's only one modification, enable inlineModificationFieldsWhenOnlyOneTypeExists()—but note that adding a second modification later will then change the schema shape and break existing queries.

Relationships and interfaces

References

A reference field's GraphQL type depends on what can legally appear there:

  • A single possible concrete type → the type itself (author: Author).
  • Multiple possible types → an interface named for the context: <Type>Entry (entry-field results), <Type>Ref (reference fields), or <Type>Embed (embedded fields). Query across them with shared interface fields, or use ... on fragments for type-specific fields.
  • Disparate types declared via @Types → a field-level interface named <Type>_<field>Ref / <Type>_<field>Embed, which only carries the global fields.

Restricted references

When a reference points to a type your endpoint configuration does not allow resolving (per referenceTypeFilter), the GCA returns a RecordRef object instead of the record: _id and _type are populated, everything else is null. The caller learns that a reference exists—and to what—without gaining access to its data.

Embedded types

Types annotated @Embedded (like our Address example) are stored inside their parent. They are always traversable when the parent is accessible, and in query-complexity calculations embedded traversal is free, whereas reference traversal costs—references require database fetches.

Field type mapping

Java typeGraphQL typeNotes
StringStringText fields with @Values constraints become enums.
boolean / BooleanBoolean! / BooleanPrimitives are non-null in output, never required in input.
int / IntegerInt! / IntSame primitive/boxed rule applies to all numbers.
long / LongLong! / LongCustom scalar—GraphQL's Int is 32-bit.
double / DoubleFloat! / FloatGraphQL Float is double-precision.
byte, short, floatByte, Short, FloatCustom scalars for the rest of the numeric tower.
java.util.DateDateSerialized as epoch milliseconds.
java.time.*Instant, LocalDate, Duration, ...ISO-8601 strings. See Built-in Types.
UUIDUUIDString form.
URI / URL / LocaleUri / Url / LocaleValidating string scalars.
List<T> / Set<T>[T]Sets serialize as lists. disallowNullCollectionItems() makes items non-null.
Map<String, T>MapOf<T>Object with entries, get(key), and json fields.
StorageItemStorageItemFiles/images: publicUrl, contentType, path, metadata(key), HTTP headers. Binary data is not inlined—download via the URL.
LocationGeoPoint{latitude, longitude}.
RegionGeoAreaPolygons/circles, GeoJSON, and WKT representations.
Rich text (@ToolUi.RichText)Marked textPlain text plus a list of marks (annotations) with positions—see Built-in Types.
Recordable subtypesobject type / interfaceSee Relationships.
MetricNot supported.

Mutation input types follow the same mapping with input-flavored counterparts (GeoPointInput, StorageItemInput, <Type>DiffRefInput for references, <Type>Diff for embedded diffs), described in Content mutations.

Schema directives

The GCA annotates the schema with directives that make it self-describing. They're visible in the SDL and queryable through standard introspection:

DirectiveWherePurpose
@bsp_type(id, internalName, embedded, abstract)types & interfacesLinks the GraphQL type to its backing ObjectType.
@bsp_field(internalName, indexed, unique, embedded)fieldsLinks a field to its ObjectField. indexed: true marks the fields usable in query predicates and sorts.
@bsp_method(internalName, indexed, unique, embedded)fieldsSame, for fields backed by an ObjectMethod.
@bsp_getterfieldsMarks a merged field whose value comes from a getter; @bsp_raw applies to these.
@bsp_raw(if: Boolean!)queriesFetch raw state instead of getter values. Cascades to child fields until overridden.

These directives are what make tooling like query builders possible without hardcoding type knowledge—see Type Introspection for the higher-level API.

Next steps

Was this page helpful?

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.