Brightspot CMS Developer Guide
Brightspot CMS Developer Guide
Developer guide
GraphQL API
Content Delivery API

Customizing field arguments in Brightspot Content Delivery API


There exist use cases where the default id and path arguments exposed in a Content Delivery API (CDA) do not fit the intended functionality. Fortunately, they are flexible!

Prerequisites
For endpoint configuration: Custom Content Delivery API development or Hello Content Delivery API.

Introduction
When exposing GraphQL APIs via Brightspot’s view system, data is typically queried for by ID or path. However, there are cases in which callers may want to query by some other criteria, like a third-party ID or maybe even remove the arguments altogether, leaving object resolution up to the view model.

Background
When it comes to removing the arguments completely, we can accomplish this by using the correct generic argument for the relevant ViewModel class. There are two ways to go about this:

  • Leverage Brightspot’s Singleton interface on your view model’s model.
  • Utilize your ContentDeliveryApiEndpoint subclass as your view model’s model.

For adding custom arguments we can leverage Brightspot’s @WebParameter annotation. It allows us to treat scalar fields, such as integers, strings, and even lists of them, as an argument.Additionally, we can create custom Java annotations that are utilized to denote a field that should be transformed into an argument with a custom input type, and even populate a Java POJO, by using ContentDeliveryApiWebAnnotationProcessor.

Examples


View model with singleton model

public class Homepage extends Content implements Singleton {
    
    private String title;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

@ViewInterface
public class HomePageViewModel extends ViewModel<Homepage> {
    
    public String getTitle() {
        return model.getTitle();
    }
}

The following types are generated in the resulting schema:

type Query {
    Homepage: Homepage
}

type Homepage {
    title: String
}

Callers are now able to query for the homepage without any arguments since the system knows how to find the one and only.

API entry field
Sometimes API designers may not need to use a data model, or may want to implement their own logic to resolve the proper data model. In this case, they can just use their endpoint class as the model for the view model.

Also, as discussed earlier, they can leverage @WebParameter to expose their own scalar arguments.

Consider the following classes:

public class Article extends Content {
    
    private String headline;

    public String getHeadline() {
        return headline;
    }

    public void setHeadline(String headline) {
        this.headline = headline;
    }
}

@ViewInterface
public class ArticleViewModel extends ViewModel<Article> {

    public String getHeadline() {
        return model.getHeadline();
    }
}

@ViewInterface
public class ArticleSearchViewModel extends ViewModel<ArticleEndpoint> {

    @WebParameter
    private String search;

    @WebParameter
    private Integer limit = 5;

    public Iterable<ArticleViewModel> getArticles() {
        Query<Article> articleQuery = Query.from(Article.class);

        if (!StringUtils.isBlank(search)) {
            articleQuery.where("* matches ?", search);
        }

        final int maxLimit = 50;

        return createViews(ArticleViewModel.class, articleQuery
            .select(0, Math.min(limit, maxLimit)).getItems());
    }
}

public class ArticleEndpoint extends ContentDeliveryApiEndpoint {

    @Override
    protected String getPathSuffix() {
        return "/article";
    }

    @Override
    public List<ContentDeliveryEntryPointField> getQueryEntryFields() {
        return Collections.singletonList(new ContentDeliveryEntryPointField(ArticleSearchViewModel.class));
    }
}

The following types are generated in the resulting schema:

type Query {
    ArticleSearch(search: String, limit: Int): ArticleSearch
}

type ArticleSearch {
    articles: [Article]
}

type Article {
    headline: String
}

The @WebParameter annotated fields are assigned to their respective argument value passed in the GraphQL query, and are utilized in the view model logic. Callers are now able to query for articles via a general full-text search.

Custom input type
API designers may want to expose a structured input type and have it populate some custom type on the back end. This is easily achievable with a custom Java annotation and a ContentDeliveryApiWebAnntoationProcessor implementation.

Consider the following classes:

public class Person {

    private String name;

    private String location;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CurrentPerson {

}

public class CurrentPersonProcessor implements ContentDeliveryApiWebAnnotationProcessor<CurrentPerson> {

    @Override
    public Object getValue(ApiRequest request, Object input, Field field, CurrentPerson annotation) {
        String name = (String) CollectionUtils.getByPath(input, "name");
        String location = (String) CollectionUtils.getByPath(input, "location");

        Person person = new Person();
        person.setName(name);
        person.setLocation(location);

        return person;
    }

    @Override
    public SchemaInputType getInputType(Field field, CurrentPerson annotation) {
        return SchemaInputTypes.newInputObject("Person")
            .field("name", SchemaInputTypes.nonNullOf(SchemaInputTypes.STRING))
            .field("location", SchemaInputTypes.nonNullOf(SchemaInputTypes.STRING))
            .build();
    }
}

public class GreetingEndpoint extends ContentDeliveryApiEndpoint {

    @Override
    protected String getPathSuffix() {
        return "/greeting";
    }

    @Override
    public List<ContentDeliveryEntryPointField> getQueryEntryFields() {
        return Collections.singletonList(new ContentDeliveryEntryPointField(GreetingViewModel.class));
    }
}

@ViewInterface
public class GreetingViewModel extends ViewModel<GreetingEndpoint> {

    @CurrentPerson
    private Person person;

    public String getGreeting() {
        return "Hello " + person.getName() + " from " + person.getLocation() + "!";
    }
}

The following types are generated in the resulting schema:

type Query {
    Greeting(person: Person): Greeting
}

type Greeting {
    greeting: String
}

input Person {
    name: String!
    location: String!
}

The @CurrentPerson annotated field is assigned to its respective argument value passed in the GraphQL query, and is utilized in the view model logic.

Previous Topic
Using Brightspot GraphQL Preview
Next Topic
GraphQL API tutorials
Was this topic helpful?
Thanks for your feedback.
Our robust, flexible Design System provides hundreds of pre-built components you can use to build the presentation layer of your dreams.

Asset types
Module types
Page types
Brightspot is packaged with content types that get you up and running in a matter of days, including assets, modules and landing pages.

Content types
Modules
Landing pages
Everything you need to know when creating, managing, and administering content within Brightspot CMS.

Dashboards
Publishing
Workflows
Admin configurations
A guide for installing, supporting, extending, modifying and administering code on the Brightspot platform.

Field types
Content modeling
Rich-text elements
Images
A guide to configuring Brightspot's library of integrations, including pre-built options and developer-configured extensions.

Google Analytics
Shopify
Apple News