Skip to main content

Get Single Content Items

The Get operation retrieves a single content item by a unique identifier, returning all fields from your Java content type class. This is the quickest way to get started with the GCA—configure your content type in the schema settings, and immediately start fetching content with full access to all object fields, nested relationships, and editorial metadata.

Get also provides built-in support for Brightspot editorial features including Preview (view shared preview content before publishing), Revisions (access historical versions), and content-backed view models (transform content for presentation via the View field). This operation returns the same content model response types used by Query and Content mutations, documented comprehensively in the Content Schema Types reference.

Configuration

Add each content type you want to fetch to your schema settings with readonlyEntryClass (or mutableEntryClass if you also need mutations). The editorial features covered later on this page are opt-in via their own settings:

1
import java.util.Set;
2
3
import com.psddev.dari.db.Recordable;
4
import com.psddev.dari.db.Singleton;
5
import com.psddev.graphql.gca.GCAEndpoint;
6
import com.psddev.graphql.gca.GCASchemaSettings;
7
8
@Recordable.DisplayName("Content API")
9
public class ContentApiEndpoint extends GCAEndpoint implements Singleton {
10
11
@Override
12
public Set<String> getPaths() {
13
return Set.of("/content-api");
14
}
15
16
@Override
17
protected GCASchemaSettings getSchemaSettings() {
18
return GCASchemaSettings.newBuilder()
19
.readonlyEntryClass(Article.class)
20
.readonlyEntryClass(Author.class)
21
.includeTypeSpecificEntryFields()
22
.includeGetRevision()
23
.includeGetPreview()
24
.build();
25
}
26
}

We'll use this Article model in the examples that follow:

1
import java.util.List;
2
3
import com.psddev.cms.db.Content;
4
import com.psddev.dari.util.StorageItem;
5
6
public class Article extends Content {
7
8
@Indexed
9
private String headline;
10
11
private String body;
12
13
@Indexed
14
private List<String> tags;
15
16
@Indexed
17
private Author author;
18
19
private StorageItem leadImage;
20
21
// Getters and setters
22
public String getHeadline() {
23
return headline;
24
}
25
26
public void setHeadline(String headline) {
27
this.headline = headline;
28
}
29
30
public String getBody() {
31
return body;
32
}
33
34
public void setBody(String body) {
35
this.body = body;
36
}
37
38
public List<String> getTags() {
39
return tags;
40
}
41
42
public void setTags(List<String> tags) {
43
this.tags = tags;
44
}
45
46
public Author getAuthor() {
47
return author;
48
}
49
50
public void setAuthor(Author author) {
51
this.author = author;
52
}
53
54
public StorageItem getLeadImage() {
55
return leadImage;
56
}
57
58
public void setLeadImage(StorageItem leadImage) {
59
this.leadImage = leadImage;
60
}
61
}
62

Anatomy of a Get query

All single-item fetching lives under the root Get field, which exposes up to three entry points:

FieldDescription
RecordFetch any configured type by unique identifier. Requires a with argument.
TypeStrongly-typed per-type fields (e.g. Type { Article(with: ...) }). Only present when includeTypeSpecificEntryFields() is enabled.
SingletonOne field per Singleton entry type, no arguments required. Only present when singleton types are configured.

The Record field (and each field under Type) returns a result object with the record's data under State plus optional editorial fields:

FieldDescription
StateThe record's fields. Use ... on fragments to select fields of the concrete type.
RevisionPaginated revision history. Requires includeGetRevision().
PreviewA shared preview of the record by preview ID. Requires includeGetPreview().
OverlayOverlay (variation) data. Requires includeGetOverlay() and the corresponding plugin.
DerivationDerived content such as translations. Requires includeGetDerivation() and the corresponding plugin.
ViewContent-backed view models. Present when view classes are configured for the type. See View Models.
lastUpdateThe record's last write time in epoch milliseconds. Useful as the readTimestamp safeguard on save mutations.

Looking up a record

The required with argument is a one-of input—provide exactly one of its fields:

LookupTypeDescription
_idUUIDThe record's unique Brightspot ID.
_url / _pathStringResolve by URL. The field is named _path when your endpoint configures a site (via siteSupplier), otherwise _url.
_typeinputNarrow the lookup to a specific concrete type, unlocking that type's unique-field lookups.
unique fieldsStringOn type-specific inputs (e.g. AuthorGetInput), every text field with a unique index becomes an alternate lookup key.

Fetching by ID looks like this:

1
query GetArticle($with: RecordGetInput!) {
2
Get {
3
Record(with: $with) {
4
State {
5
__typename
6
_id
7
_label
8
... on Article {
9
headline
10
body
11
tags
12
author {
13
... on Author {
14
name
15
}
16
}
17
}
18
}
19
lastUpdate
20
}
21
}
22
}
23

To fetch the same article by its public URL instead, change only the variables:

1
{ "with": { "_url": "/welcome-to-brightspot" } }
tip

Unique-field lookups are great for natural keys. The Author model declares email with @Indexed(unique = true), so Get { Type { Author(with: {email: "jane@example.com"}) } } fetches the author without knowing their ID.

Type-specific fields

With includeTypeSpecificEntryFields() enabled, every entry type also gets a strongly-typed field under Get/Type. The lookup input is specific to the type (e.g. ArticleGetInput), unique-field lookups appear as top-level input fields, and the returned State is typed directly to the entry type:

1
query GetArticleTyped($with: ArticleGetInput!) {
2
Get {
3
Type {
4
Article(with: $with) {
5
State {
6
headline
7
}
8
}
9
}
10
}
11
}

This costs schema size—one field and input type per entry type—but gives consumers better autocompletion, simpler queries (no ... on fragments), and compile-time safety in generated clients.

Singletons

Types implementing Singleton (site settings, global configuration, etc.) appear under Get/Singleton as argument-less fields, since there is only ever one instance:

1
{
2
Get {
3
Singleton {
4
SiteConfig {
5
State {
6
... on SiteConfig {
7
companyName
8
}
9
}
10
}
11
}
12
}
13
}

By default, singletons are only fetchable here—they are excluded from Query entry fields. Enable allowQueriesOnSingletonEntryFields() if you need to query them like regular content.

Revisions

With includeGetRevision() enabled, the Revision field exposes a record's revision history with standard pagination:

ArgumentTypeDescription
typeRevisionTypeFilter to a single revision type: History (published revisions), Revision (drafts), MergedRevision, or WorkflowLog.
offsetLongPagination offset. Defaults to 0.
limitIntPage size. Subject to the same default/maximum limits as queries.

Each revision item exposes its id and the revision record itself via state. Revision types that capture a full copy of the content—History and Revision (drafts)—also expose the record as it existed at that revision via object on their concrete item types:

1
query GetArticleRevisions($with: RecordGetInput!) {
2
Get {
3
Record(with: $with) {
4
Revision(type: History, offset: 0, limit: 5) {
5
items {
6
id
7
... on Record__HistoryItem {
8
object {
9
... on Article {
10
headline
11
}
12
}
13
}
14
}
15
pageInfo {
16
count
17
hasNext
18
}
19
}
20
}
21
}
22
}
23
note

History revisions are created when content is published by a CMS user. Content saved programmatically without user attribution does not generate revision history, so a freshly-migrated dataset may return empty results here.

Previews

With includeGetPreview() enabled, the Preview field fetches a shared preview by its ID—the same previews editors create from the CMS content edit page:

1
{
2
Get {
3
Record(with: {_id: "..."}) {
4
Preview(id: "00000000-0000-0000-0000-000000000000") {
5
object {
6
... on Article {
7
headline
8
}
9
}
10
}
11
}
12
}
13
}

The object field returns the record with the preview's changes applied, and preview returns the preview record's own metadata. When view classes are configured, a View field is also available so you can render the preview through the same view models used for live content—this is the foundation for real-time front-end preview experiences.

Overlays and derivations

Two more editorial integrations are available behind settings, both of which depend on optional plugins being present in your project:

  • Overlay (includeGetOverlay()) — fetch overlay data (e.g. segmented variations of content) by overlay ID or provider ID.
  • Derivation (includeGetDerivation()) — traverse derived content such as machine or human translations of the record.

Detecting conflicting writes

Every Get result includes lastUpdate, the time the record was last written. If your application fetches content, lets a user edit it, and saves it back, pass that value as the readTimestamp argument of the save mutation. The save will fail if someone else modified the affected fields in the meantime, signaling your application to re-fetch and retry. See Content mutations for details.

Next steps

Was this page helpful?

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