Topics

GraphQL reference topics


In This Guide

This section provides reference information for the GraphQL features used with Brightspot.


CDA vs. CMA: Which one should we use?

Introduction

Brightspot offers two main APIs for generating GraphQL endpoints: ContentDeliveryApiEndpoint (CDA) and ContentManagementApiEndpoint (CMA). There is overlap in functionality between these two solutions, which can make it unclear as to what the right choice is. It is important to consider the names of the two APIs when evaluating them against a use case. CDAs are focused on delivering data to some downstream user, many times, via a frontend like a web browser or native application. CMAs are focused on managing CMS data and support much more internal business use cases like automated testing, data ingestions and exports, and powering custom CMS user interfaces. Although the distinction between “delivery” and “management” seems to imply that the former is for only for reading, they both have the ability to expose CRUD operations for Brightspot data, so data manipulation should not be the only factor taken into consideration.

Content Delivery API

CDAs focus on exposing only what is necessary to power a specific experience. They expose mostly high-level Brightspot features, providing simple GraphQL APIs that are intuitive to implement.

View

CDAs can leverage Brightspot’s view system to provide a transformation layer for data before it is presented to the end user. This is very important for situations in which raw data from the database may need to stripped of internal information or transformed into a specific format. Conversely, the transformation layer is also great for cleaning and saving UGC (user-generated content) data input via the mutation GraphQL APIs that the CDA can expose. Additionally, developers have immense freedom in designing and customizing CDA APIs to reflect very specific intended schemas.

Recordable

Sometimes the transformation layer is not necessary, and an API designer may want to pass modeled data straight through. CDAs can be configured with Brightspot types to take that extra step out of the process.

Content Management API

CMAs focus on exposing Brightspot concepts and APIs via GraphQL. This allows a caller to replicate much of the functionality available, through Java code, directly with the generated APIs. The extra functionality makes CMAs have a heavier footprint than a typical CDA and also far less customizable; however, callers have the ability to read and mutate most Brightspot data with only a simple endpoint configuration necessary on the backend.


Authentication

How to create an API Client, furnish an API Key, set their permissions, and how to make requests on their behalf.

Overview

When creating a GraphQL endpoint, you may wish to restrict who has access to submit queries. With Brightspot’s GraphQL authentication features, you can control which clients have access to an endpoint, as well as what sites each client can retrieve content from.

Creating an API client

An API Client object represents an entity that has access to Brightspot’s GraphQL endpoints. The fields on the client object will determine what Sites it has access to, what endpoints it can query, and what API Keys it is associated with. To create an API Client, navigate to Admin > APIs in Brightspot and click New API Client on the left menu.

Endpoint permissions

Under the Endpoints section, you can enumerate what GraphQL endpoints this client can access. For endpoints that are configured to require API Key access, your client will also need to have an API Key associated with it in order to retrieve content from the endpoint.

Sites permissions

For detailed information about Sites Permissions, see Sites permissions.

Custom permissions

Developers may also create their own custom permissions by extending the ApiPermission class and implementing the hasPermission method. Note that in order for a client to access data from an endpoint, the request must satisfy all permissions associated with the client.After configuring your API Client’s permissions, click Save. Your client is now ready to make requests to your endpoint.

API keys

GraphQL endpoints can be configured to require an API Key for access. For external applications to access such a GraphQL endpoint, they must use a client’s API Key. This key is a unique identifier that verifies the authenticity of the entity making the request and applies the corresponding permissions.

Furnishing an API key

To generate an API Key for a client, click the name of the desired client from the left menu of the APIs Dashboard. Under the Keys section, click Add API Key and an API key for this client will be generated. Click the clipboard icon to copy the API key to your clipboard; it will not be available once you leave this page. Click Save once you have copied the key.

Making requests from a client

When making requests with an API Key, the X-API-Key header should be included on the request. The value of this header will be the key generated in the previous section. If the X-API-Key header is not included in the request, Brightspot will attempt to retrieve the apiKey query string parameter from the request URL. If no API Key can be resolved, the request will not execute and an error will be returned.


Cross-Origin Resource Sharing

What CORS is and how to configure it in your application.

Introduction to CORS

Cross-Origin Resource Sharing (CORS) is a mechanism that allows requests for data from one domain to be retrieved by another domain. Ordinarily, under the same-origin security policy, AJAX requests that target a domain other than the one serving the current page would fail. This is done for a variety of reasons; from simply disabling modification access (e.g. POST or DELETE requests) from foreign domains, to preventing malicious scripts from retrieving sensitive data used by one domain and sending it to another. To ensure safe cross-domain communication, CORS sets up a protocol through the use of HTTP headers and preflight requests. For more information on the CORS protocol, see MDN’s CORS documentation.

Brightspot, GraphQL, and CORS

Brightspot GraphQL endpoints allow for a CORS Configuration with Allowed Origins and Allowed Headers settings.Any cross-domain request made to a GraphQL endpoint has its origin domain compared with those in the Allowed Origins. For any request from an allowed origin, the response will include the Access-Control-Allow-Origin header, with the value set to the origin that the request originated from. Additionally, any preflight OPTIONS requests made to the endpoint will include the Access-Control-Allow-Headers header in the response. The value of the header will specify what additional non-default headers, based on the Allowed Headers configuration, may be included in a cross-origin request. All endpoints allow Content-Type, X-API-Key, and X-Site headers.

Because the CORS protocol is automatically implemented by the browser, no additional configurations are required to make a request to GraphQL endpoints in a client application. As long as the request comes from an allowed origin and contains only valid headers, cross-origin requests will execute safely and without issue.


Persisted queries

How to configure persisted queries on your endpoint and the protocol for using them.

Introduction to GraphQL persisted queries

GraphQL queries are an effective method of retrieving data, but the repeated transmission of complex queries hampers network performance due to their length. To remedy this, persisted queries allow client applications to send a hash of a query to Brightspot in place of the full query text. This reduced payload size allows for quicker network transmission between the client and server, while still retrieving the same data. Additionally, this reduced size enables GraphQL queries to be sent via HTTP GET. This allows CDNs to cache the result, further improving performance.

The Persisted Query Protocol

The persisted query protocol, as described by Apollo, defines the interactions between client and server when passing query hashes. Simply put, the GraphQL client makes a request containing the hash of its desired query to a Brightspot GraphQL endpoint. If the endpoint recognizes the hash, it will execute the desired query and send the result back to the client in the response.

How does the Persisted Query Protocol work?

Consider the following query to retrieve the articleBody data of an Article at a given path via a Content Delivery API endpoint:

query ArticleQuery($path: String) {

ArticlePage(path: $path) {

headline

}

}

with the variables:

{

"path": "/article-path"

}

The steps for executing this request via the Persisted Query Protocol are as follows:

  • The client sends a hash of the query to execute, plus any variables necessary to complete the request. This can be sent via URL parameters in an HTTP GET request, or in the body of an HTTP POST request.

    GET URL Path:

    /graphql/delivery/article?variables=%7B%22path%22%3A%22%2Farticle-path%22%7D&extensions=%7B%22persistedQuery%22%3A%7B%22sha256Hash%22%3A%22c205cf782b5c43c3fc67b5233445b78fbea47b99a0302cf31bda2a8e2162e1e6%22%7D%7D

Alternative POST Body:

{
  "variables": {
    "path": "/article-path"
  },
  "extensions": {
    "persistedQuery": {
      "sha256Hash": "c205cf782b5c43c3fc67b5233445b78fbea47b99a0302cf31bda2a8e2162e1e6"
    }
  }
}

If Brightspot recognizes this hash (either from seeing it in a previous request for Automatic Persisted Queries, or by fetching it from a designated Static Query Mapping), it will execute the associated query and return the results. However, if it does not recognize the hash, an error will be returned instead:

{
  "errors": [
    {
      "message": "PersistedQueryNotFound"
    }
  ]
}

The client’s expected response at this point will be dependent on the endpoint’s persisted query configuration.

  • If configured with Static Query Mapping, receiving this error means that the query associated with this hash is not authorized to execute against this endpoint. As such, there is no further communication expected between client and server. Attempting to pass the unsupported query/hash combination (in the format of the APQ example below) in a request will result in a PersistedQueryNotSupported error being returned by the endpoint.
  • If configured with Automatic Persisted Queries, then the following steps will take place:

The client sends an HTTP POST request with the same hashed value along with its corresponding query.
POST Body:

{
  "query" : "query ArticleQuery($path: String) {\n  ArticlePage(path: $path) {\n    headline\n  }\n}",
  "variables" : {
    "path" : "/article-path"
  },
  "extensions" : {
    "persistedQuery" : {
      "sha256Hash" : "c205cf782b5c43c3fc67b5233445b78fbea47b99a0302cf31bda2a8e2162e1e6"
    }
  }
}

Brightspot validates the hash. If the sha256hash parameter matches the calculated hash of the passed query, Brightspot stores the query, processes the request, and returns the result.

{
  "data": {
    "Article": {
      "headline": "Hello World"
    }
  }
}

If the hash is successfully validated, any future requests to execute this query may omit the query string in favor of its hash, as defined in Step 1.

Configuring Brightspot with persisted queries

To enable persisted queries, navigate to your desired endpoint and locate the Persisted Query Protocol field. Brightspot GraphQL endpoints support two methods of Persisted Queries: Static Query Mapping and Automatic Persisted Queries. The differences between the two are as follows:

Static query mapping

If you want to configure your Brightspot endpoint to only accept a specific set of GraphQL queries, then enabling Static Query Mapping as your endpoint’s Persisted Query Protocol is appropriate. You will be able to upload a JSON containing a map of each query key and its corresponding query that the server will run. If a requested key is not recognized, the server will respond with an error and no query will execute.

Automatic persisted queries

On the other hand, if you want your GraphQL endpoint to accept and persist more than a predefined set of queries, the Automatic Persisted Queries (APQ) protocol will allow you to do so. For APQ, the client still sends a query hash to Brightspot when making a request. However, if Brightspot doesn’t recognize the hash, it will instruct the client to resend the full query. Upon the client sending the query and its associated hash, Brightspot will save that mapping so all future requests for that query only need to send the hash.

Maintaining APQ mapping parity with Brightspot

Brightspot’s GraphQL Explorer tool allows developers to see the expected parameters when performing requests via the Persisted Query Protocol.

After inserting a query into Brightspot’s GraphQL Explorer, clicking the gear icon in the top right and selecting Persisted Query Extension will display the GET URL path and POST Body for the requests defined in steps 1 and 3 above. Clicking on the “Advanced” tab will display an additional minified POST body to further reduce the size of requests made by your application. Use this tool to verify that your application’s request parameters match those that Brightspot expects to receive for the specified query.

Configuring client applications with persisted queries

The tools linked in the examples below are for use with Apollo applications. While similar tools may be available for other GraphQL clients, Apollo has the most directly applicable integrations with Brightspot’s offerings.

Static query mapping

For Static Query Mapping, the PersistGraphQL library allows you to extract all the GraphQL queries used within your application to a JSON file that can be uploaded to Brightspot. By default, this tool makes the key to each query an auto-incrementing integer as opposed to a hash. This will still work with Brightspot, but if you prefer to have an SHA-256 hash associated with each query instead, the PersistGraphQL Signature Sync script will allow you to do so.

Automatic persisted queries

For APQ, the Apollo Link Persisted Queries library provides an extension for an HttpLink (or a custom Apollo Link) to allow for the APQ protocol to take place.


Sites permissions

How to limit access to the data that clients can retrieve from your GraphQL endpoints to specific Sites.

Configuring sites permissions for a client

A client may be configured with Sites permissions that determine which sites the client has access to. To modify the Sites permissions for a client, navigate to the APIs Dashboard and select the desired client from the left menu.

Under Permissions, click Add Sites to add a Sites permission. Then, add the sites that you want your client to have access to and click Save.

A few notes here:

  • If you don’t add a Sites permission, the client will have access to all sites.
  • If you add one or more sites under the same Sites permission, the client will have access to the sites listed.
  • If you add multiple Sites permissions to a client, the client will only have access to sites that are in each permission.

Making requests with multiple sites

When querying an API endpoint, the site should be specified in the request via the X-Site header or the site query string parameter in the request URL. The value of this field should be the URL or ID of the desired Site as displayed in Sites & Settings.

If both the X-Site header and site query string parameter are provided, the query string value will take precedence over the header value.

Including the Site parameter in your request is not mandatory, but if your client has access to more than one Site, the endpoint will be unable to determine the appropriate Site for your request and will return an error. The one caveat to this is if your client has global site permissions, in which case all content accessible to the global site can be retrieved. If your client only has access to one Site, then that available Site will be used by default, even if the Site parameter is not passed.

When using a CMA endpoint to create a piece of content, the Site that is passed (or automatically determined) will be assigned as that content’s owner site. Additionally, if you attempt to update a piece of content, but the Site passed does not match the Site that owns the content, an error will be returned and the content will not be updated. The exception to this is if the client making the request has global permissions and does not pass a Site in the request. In that case, the content’s owner site will be used as the site for the request.