GraphQL Content API
Introduction
The GraphQL Content API provides a GraphQL API interface to the content from Contentful. Each Contentful space comes with a GraphQL schema based on its content model. This GraphQL schema is generated at request time and is always up-to-date with the current status of the space.
You can use this API to consume both published and non-published content. Read more about this in the previewing content section.
Basic API information
https://graphql.contentful.com
Basic API Information
The Contentful GraphQL Content API is available at:
https://graphql.contentful.com/content/v1/spaces/{SPACE}
It is also available for specific environments at:
https://graphql.contentful.com/content/v1/spaces/{SPACE}/environments/{ENVIRONMENT}
HTTP Methods
The GraphQL Content API supports both GET and POST methods.
This is the query used in both examples below:
query($preview: Boolean){
blogCollection(preview: $preview){
items{
title
}
}
}
POST
The HTTPS POST method is more flexible and recommended. The query should be sent as a property in a JSON payload in the body of the POST request with the property name "query". Any required variables are added as an additional JSON property to the payload with the property name "variables".
curl -g \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {TOKEN}" \
-d '{"query":"query($preview:Boolean){blogCollection(preview:$preview){items{title}}}","variables":{"preview":true}}' \
https://graphql.contentful.com/content/v1/spaces/{SPACE}/environments/{ENVIRONMENT}
Supported values for Content-Type
header are listed below:
application/json
application/json; charset=UTF-8
.application/x-www-form-urlencoded
.application/x-www-form-urlencoded; charset=UTF-8
Using application/json
is encouraged.
GET
The HTTPS GET method requires that the query is included in the URL string as a parameter. You can also send any required variables in an additional "variables" parameter in JSON format.
curl -g \
-X GET \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {TOKEN}" \
'https://graphql.contentful.com/content/v1/spaces/{SPACE}/environments/{ENVIRONMENT}?query=query($preview:Boolean){blogCollection(preview:$preview){items{title}}}&variables={"preview":true}'
Authentication
Any client using the API needs to provide an access token in either:
The
Authorization
header, specifically,Authorization: Bearer MY_TOKEN
.The
access_token
URL query parameter.
The token must have access to the space and environment you're targeting.
For example, if you create an access token that only has access to the master
environment of your space, you cannot use that token to access content from any
other environment or space.
To learn more about authentication in Contentful and how to create your own access tokens take a look at the Authentication reference documentation.
API rate limits
API Rate limits specify the number of requests a client can make to Contentful APIs in a specific time frame. Every request counts against a per-second rate limit.
There are no limits enforced on requests that hit our CDN cache, i.e. the request doesn't count towards your rate limit and you can make an unlimited amount of cache hits. For requests that do hit the GraphQL Content API, a rate limit of 55 requests per second is enforced. Higher rate limits may apply depending on your current plan.
When a client gets rate limited, the API responds with the 429 Too Many Requests HTTP status code
and sets the X-Contentful-RateLimit-Reset
header that tells the client when it can make its next single request.
The value of this header is an integer specifying the time before the limit resets and another request will be accepted.
As the client is rate-limited per second, the header will return 1, which means the next second.
Example
The current rate limit for a client is the default 55 per second. Client: 85 uncached requests in 1 second
HTTP/1.1 429
X-Contentful-RateLimit-Reset: 1
Meaning: wait 1 second before making more requests.
Query complexity limits
Query complexity limits specify the amount of data a client can request from the GraphQL Content API in one request. You can currently request up to 11000 entities in one request.
Example 1
query {
lessonCollection(limit: 20) {
items {
title
}
}
}
The query above can return up to 20 Lessons
. The query complexity is 20.
Example 2
query {
lessonCollection(limit: 20) {
items {
title
imageCollection(limit: 10) {
title
url
}
}
}
}
The query above can return up to 20 Lessons
and up to 200 Assets
(up to 10 for each of 20 Lessons
).
The query complexity is 220.
Example 3
query {
lessonCollection(limit: 20) {
items {
title
participantsCollection (limit: 10) {
... on Person {
name
imageCollection(limit: 3) {
title
url
}
}
... on Pet {
name
imageCollection(limit: 5) {
title
url
}
}
}
}
}
}
The query above can return up to 20 Lessons
, up to 200 Participants
(up to 10 for each of 20 Lessons
)
and up to 1000 Assets
(up to 5 for each of 200 Participants
). The query complexity is 1220.
Parameters such as locale, preview, sorting, filtering or image transformations do not change query complexity.
The API sets the X-Contentful-Graphql-Query-Cost
response header to the calculated query complexity value.
When a client gets query complexity limited, the API responds with a TOO_COMPLEX_QUERY
error.
Query size limits
Query size limits specify the maximum size of the query parameter for GET requests and the total payload size for POST requests. This limit is 8kb.
This limit includes whitespace and newline characters. Removing semantically unnecessary whitespaces and newline characters before sending a request can lower the query size. You can reduce the query size without manual editing using GraphQL minifiers, such as GQLMin.
When the query size of a request exceeds the limit, the API returns a QUERY_TOO_BIG
error.
Rich Text
Rich Text fields work similarly when calculating complexity but have some special behaviour. The complexity
of the links
property in a RichText
field is equal to the sum of the maximum number of allowed linked
entries and assets in the validation settings for the field.
In the following example the richText
field is configured with a maximum limit of 5 embedded inline entries and
a maximum of 0 of all other types of embedded entries or assets:
Example
query{
articleCollection(limit: 100) {
items{
title
bodyRichText {
json
links {
entries {
inline {
sys {
id
}
}
}
}
}
}
}
}
The query above can return up to 100 article
entries and up to 500 links
(up to 5 for each of 100 article
) due to the field validation settings. The query complexity is 500.
By default a Rich Text field has a total limit of 1000 linked entities of all supported types.
This means that by default the links
field in each Rich Text entry has a complexity of 1000.
The complexity is calculated as the maximum number of entries and assets a query can potentially return.
Tags
The ContentfulMetadata tags field calculates its complexity in a special way.
The complexity of the tags property in the ContentfulMetadata
field is 1 for every entry or asset being queried for.
This complexity cost remains the same regardless of the number of tags returned.
Example
query {
articleCollection(limit: 100) {
items{
title
contentfulMetadata {
tags {
id
name
}
}
}
}
}
The query above can return up to 100 Articles
and up to 100 tags (up to 1 for each of 100 Articles
).
The query complexity is 200.
Previewing content
Accessing non-published content can be useful when you want to, for example, preview how a new article will look before publishing it and making it public to everybody. The GraphQL API gives you the control to choose whether you want to access published or non-published content in a very granular fashion.
To control whether you get published or non-published content you have to use
the preview
argument, available to both the single resource
fields and collection
fields. This argument cascades,
meaning that all the references resolved from a resource with preview: true
are also showing preview content, unless explicitly overridden. So for example
the root level could use non-published content while a sub resource could use
published content. This is explained in the example below:
query {
houseCollection (preview: true) {
items {
// "house" fields will use non published content
houseNumber
numberOfRooms
owner {
... // content for the "owner" will also be non published
}
architect (preview: false) {
... // content for the "architect" will be published
}
}
}
}
Any query that accesses non published content requires a preview access token.
This includes queries that mix preview and published content.
Follow the authentication section to
learn how to generate a token and how to use it to authenticate the requests.
Fields in queries that require access to non-published content but fail to
provide a valid preview access token will be resolved with an
ACCESS_TOKEN_INVALID
error.
Reference
Locale handling
You can specify a locale via the locale
argument on collections, single entities, and entry fields:
query {
germanUser: friendlyUser(id: "hans", locale: "de-DE") {
name
}
americanUser: friendlyUser(id: "joe", locale: "en-US")
}
If you don't specify a locale, the default locale of the space is used.
Unlike the CDA, the GraphQL Content API does not support the locale wildcard.
This argument cascades, meaning that all the references resolved from a
resource with locale: "de-DE"
will also show German content unless
explicitly overridden. So for example the root level could use a different
locale than a sub resource. When changing the locale on references, only the
referenced entities are resolved with this locale. The reference field value
itself is still resolved with the locale of the parent.
This is explained in the example below:
query {
germanUser: friendlyUser(id: "hans", locale: "de-DE") {
name
germanPetsInFrench: petsCollection(locale: "fr-FR") {
items {
name
}
}
}
}
Individual fields can also have a locale specified, giving the ability to fetch the same field in multiple locales using query aliases.
query {
germanUser: friendlyUser(id: "hans", locale: "de-DE") {
name
petsCollection {
items {
name
nameInFrench: name(locale: "fr-FR")
}
}
}
}
If requested locale does not exist, an UNKNOWN_LOCALE
error is returned for this path.
Schema generation
The GraphQL schema definition is generated from the content model at request time so it is always current.
Types
The GraphQL schema is generated from the content types defined in the specified
environment of the space
(or master
if no environment has been specified). For each content type in your environment the
GraphQL Content API creates a corresponding GraphQL type.
Names
Type name is the pascalcase version of the content type ID, stripped of non-alphanumeric characters. For example:
Original value | Transformed value |
---|---|
"my-2content-type" | "My2ContentType" |
If two or more content type IDs would be transformed to the same type name, a COLLIDING_TYPE_NAMES
error is returned.
For more information about errors see the errors section.
If the generated name starts with a number or collides with a reserved type name, it gets prefixed with 'ContentType'. For example:
Original content type id | Transformed type name |
---|---|
Location |
ContentTypeLocation |
5TbTQ4S6xqSeAU6WGQmQ2e |
ContentType5TbTQ4S6xqSeAU6WGQmQ2e |
In order to keep the original name in query response, consider using aliases like:
query {
location: contentTypeLocation(id: "some-id") {
# ... location fields
}
}
Reserved type names
Query
, String
, Int
, Float
, Boolean
, Location
, Circle
, Rectangle
, DateTime
, RichText
,
Asset
, AssetCollection
, AssetLinkingCollections
, AssetFilter
, AssetOrder
,
Entry
, EntryCollection
, EntryOrder
, Sys
, SysFilter
, ContentfulMetadata
, ContentfulTag
,
ContentfulMetadataFilter
, ContentfulMetadataTagsFilter
, Dimension
, HexColor
, Quality
, ImageResizeFocus
,
ImageResizeStrategy
, ImageFormat
, ImageTransformOptions
, ResourceSys
, ResourceLink
, ResourceLinkCollection
and
Never
.
Example
For example, a single content type is defined as following:
{
sys: {
id: "friendly-user"
},
fields: [
...
]
}
Using this content type definition, the API calls automatically generates the
corresponding schema definition. Notice how the GraphQL type is named after the content
type ID. The produced Query
object exposes two fields that you can
use to query content of that type: one for fetching individual content docs
(friendlyUser
in the example) and another to do queries over all the content
of the type (friendlyUserCollection
). Collections are explained in more detail
in the Collections section.
type Sys {
id: String
spaceId: String
environmentId: String
}
type ContentfulMetadata {
tags: [ContentfulTag]!
}
type ContentfulTag {
id: String!
name: String!
}
type FriendlyUser {
sys: Sys
contentfulMetadata: ContentfulMetadata
# ... fields
}
input FriendlyUserFilter {
# ... field based filters
}
type FriendlyUserCollection {
skip: Int!
limit: Int!
total: Int!
nodes: [FriendlyUser]!
}
type Query {
friendlyUser(id: String!): FriendlyUser
friendlyUserCollection(
skip: Int
limit: Int,
where: FriendlyUserFilter
): FriendlyUserCollection
}
Fields
GraphQL type fields are generated from the corresponding content
type fields. Each type has three additional fields: sys
, contentfulMetadata
and linkedFrom
.
Names
Field name is the lower camelcased version of the field ID, stripped of non-alphanumeric characters. For example:
Original value | Transformed value |
---|---|
"my-field8-name" | "myField8Name" |
If two or more field IDs on the same content type would be transformed to the same field name, a COLLIDING_FIELD_NAMES
error is returned.
If the generated name collides with a reserved field name, a RESERVED_FIELD_NAME
error is returned. Reserved field names are sys
, contentfulMetadata
and linkedFrom
.
For more information about errors see the errors section.
Types
Field type is determined based on the following mappings:
Contentful type | GraphQL Type |
---|---|
Symbol |
String |
Text |
String |
Number |
Float |
Integer |
Int |
Date |
DateTime |
Boolean |
Boolean |
Object |
JSON |
Array of Symbol |
[String] |
Fields of type Link
and Array of Link
are handled as explained in Modeling
relationships.
Fields of type Location
are handled as explained in Locations.
Fields of type RichText
are handled as explained in Rich text.
Fields of type Never
are handled as explained in Never.
Arguments
Fields on entries provide an optional locale
argument, allowing the locale to be overridden for a single
field. The current scope's locale is used if a locale is not specified. If the requested locale does not exist,
an UNKNOWN_LOCALE
error is returned for this path.
Example
Next, continue with the previous example and extend the Friendly User
content type with three fields: age
, name
and addresses
.
{
name: "Friendly User"
sys: {
id: "friendly-user",
...
},
fields: [
{
id: "age",
type: "Integer"
},
{
id: "name",
type: "Symbol"
},
{
id: "addresses",
type: "Array",
items: {
type: "Symbol"
}
}
]
}
The resulting GraphQL schema is:
type FriendlyUser {
sys: Sys
contentfulMetadata: ContentfulMetadata
linkedFrom: FriendlyUserLinkingCollections
age(locale: String): Int
name(locale: String): String
addresses(locale: String): [String]
}
Schema generation failure
Schema generation fails when:
Two or more content type IDs would be transformed to the same type name.
Two or more field IDs on the same content type would be transformed to the same field name.
Any field ID would be transformed to
sys
,contentfulMetadata
orlinkedFrom
field name.
You cannot change the content type ID without regenerating the content type, so be aware of these restrictions while creating your content models.
Colliding type names
In order to successfully generate the schema, the GraphQL type generated from a content type id has to be unique.
Type uniqueness check will fail if a content type id is transformed into a GraphQL type that already exists.
This can happen in two cases:
when two or more content type ids are transformed into the same GraphQL type name
when a content type id is transformed into a GraphQL type name that collides with the existing GraphQL helper type
While the first case is straightforward, let's take a closer look at the second case.
GraphQL generates the following helper types for each content type:
Collection
LinkingCollections
Filter
Order
For a content type Plants
with id plants
, GraphQL will generate type Plants
and the following helper types:
PlantsCollection
PlantsLinkingCollections
PlantsFilter
PlantsOrder
If we happen to have a second content type called PlantsOrder
with id plantsOrder
, schema creation will fail. The GraphQL type PlantsOrder
will collide with the PlantsOrder
helper type generated for Plants
content type.
To avoid type name collisions for a new content type, make sure that the GraphQL types and helper types generated for it won't collide with any of the existing GraphQL types.
Sys field
Each GraphQL type is derived from a content type and the Asset
type will also
have a system-defined sys
field. This field exposes meta-information about the content.
type Sys {
id: String!
spaceId: String!
environmentId: String!
publishedAt: DateTime
firstPublishedAt: DateTime
publishedVersion: Int
}
type MyContentType {
... # content fields
sys: Sys!
}
type Asset {
... # content fields
sys: Sys!
}
The table below describes each of the fields in the GraphQL Sys
type
Field | Type | Description |
---|---|---|
id |
String |
Unique identifier of the resource. |
spaceId |
String |
Unique identifier of the resource's space. |
environmentId |
String |
Unique identifier of the resource's environment. |
publishedAt |
DateTime |
DateTime string of the resource's last published time. |
firstPublishedAt |
DateTime |
DateTime string of the resource's first published time. |
publishedVersion |
Int |
The version of the draft resource when it was published. |
ContentfulMetadata field
Each GraphQL type derived from a content type and the Asset
type will also
have a contentfulMetadata
field. This field exposes information on the public tags that exist on the content.
To learn more about tags, see the tags section in our API reference page.
type ContentfulMetadata {
tags: [ContentfulTag]!
}
type ContentfulTag {
id: String!
name: String!
}
type MyContentType {
... # content fields
contentfulMetadata: ContentfulMetadata
}
type Asset {
... # content fields
contentfulMetadata: ContentfulMetadata
}
The table below describes each of the fields in the GraphQL ContentfulMetadata
type
Field | Type | Description |
---|---|---|
id |
String |
Unique identifier of the tag. |
name |
String |
The resolved tag name. |
Modeling relationships
One of the benefits of GraphQL is that it simplifies traversing the graph of relationships between different types.
In Contentful, relationships are modeled using links. An entry
field can be a link to another entry or a list of links to other entries. The content
type of the entries that can be linked from a given field can be restricted
using the linkContentType
validation. Although optional,
it is recommended to define linkContentType
for your link fields for a better experience.
The GraphQL schema uses this validation to determine the type of a link field.
A field may also link to an asset by specifying linkType: "Asset"
. In this
case there is no linkContentType
validation, the GraphQL type of the field is always Asset
.
The following sections explain in detail how different kinds of relationships are modeled and how the corresponding GraphQL schema functionality looks.
One-to-one single-type relationships
One-to-one single-type relationships are modeled by content type fields that
link to at most one entry of a fixed type. For example, each FriendlyUser
entry
has a manager
field that links to one entry of content type FriendlyUser
.
{
name: "Friendly User"
sys: {
id: "friendly-user",
...
},
fields: [
...,
{
id: "manager",
type: "Link",
linkType: "Entry",
validations: [{ linkContentType: ["friendlyUser"] }]
}
]
}
This results in the following schema:
type FriendlyUser {
sys: Sys
contentfulMetadata: ContentfulMetadata
manager: FriendlyUser
# ... other fields
}
One-to-one multi-type relationships
It is possible for an entry field to link to entries of different content types.
For example, each FriendlyUser
may have a pet that is either a Dog
or a
Cat
. This is modeled with the following content types.
{
name: "Cat",
sys: {
id: "cat",
...
}
}
{
name: "Dog",
sys: {
id: "dog",
...
}
}
{
name: "Friendly User"
sys: {
id: "friendly-user",
...
},
fields: [
...,
{
id: "pet",
type: "Link",
linkType: "Entry",
validations: [{ linkContentType: ["cat", "dog"] }]
}
]
}
This results in the following schema:
type Dog {
# ...
}
type Cat {
# ...
}
union FriendlyUserPet = Cat | Dog
type FriendlyUser {
sys: Sys
contentfulMetadata: ContentfulMetadata
age: Int
name: String
addresses: [String]
petsCollection: FriendlyUserPetsCollection
manager: FriendlyUser
# ...
pet: FriendlyUserPet
}
One-to-many single-type relationships
One-to-many relationships are modeled with arrays of links. For example, a
FriendlyUser
might have multiple friends.
{
name: "Friendly User"
sys: {
id: "friendly-user",
...
},
fields: [
...,
{
id: "friends",
type: "Array",
items: {
type: "Link",
linkType: "Entry",
validations: [{ linkContentType: ["friendlyUser"] }]
}
}
]
}
In the resulting GraphQL schema the friends
field is renamed to friendsCollection
and is of a collection type, the
same type that is used for top-level collections for the FriendlyUser
content type. The field has the same skip
and limit
arguments as the
top-level collection field and the same limits apply.
type FriendlyUser {
sys: Sys
contentfulMetadata: ContentfulMetadata
friendsCollection(skip: Int, limit: Int): FriendlyUserCollection
# ...
}
type FriendlyUserCollection {
skip: Int!
limit: Int!
total: Int!
items: [FriendlyUser]!
}
One-to-many multi-type relationships
As with one-to-one relationships, a collection field can link to entries of
different content types. For example, a FriendlyUser
can have multiple pets,
each of which is either a Dog
or a Cat
.
{
name: "Cat",
sys: {
id: "cat",
...
}
}
{
name: "Dog",
sys: {
id: "dog",
...
}
}
{
name: "Friendly User"
sys: {
id: "friendly-user",
...
},
fields: [
...,
{
id: "pets",
type: "Array",
items: {
type: "Link",
linkType: "Entry",
validations: [{ linkContentType: ["dog", "cat"] }]
}
}
]
}
This results in the following schema:
type Dog {
# ...
}
type Cat {
# ...
}
union FriendlyUserPetsItem = Cat | Dog
type FriendlyUserPetsCollection {
skip: Int!
limit: Int!
total: Int!
items: [FriendlyUserPetsItem]!
}
type FriendlyUser {
sys: Sys
contentfulMetadata: ContentfulMetadata
petsCollection(skip: Int, limit: Int): FriendlyUserPetsCollection
# ...
}
Links to a specific item
You can retrieve the collection of entries linking to a specific entry (or asset)
by using the linkedFrom
field in your query.
For example, consider a Friendly User
content type defined as follows:
{
name: "Friendly User"
sys: {
id: "friendly-user",
...
},
fields: [
...,
{
id: "photo",
type: "Link",
linkType: "Asset"
},
{
id: "pets",
type: "Array",
items: {
type: "Link",
linkType: "Entry",
validations: [{ linkContentType: ["dog", "cat"] }]
}
}
]
}
Friendly User
links to the Asset
type through the photo
field, which is a link to an asset. It also links to the Dog
and Cat
types
through the pets
field, which is a list of links to entries, with content types restricted to Dog
and Cat
.
Based on those relationships, a friendlyUserCollection
field is generated inside the linkedFrom
fields of the Asset
, Dog
, and Cat
types:
type Cat {
sys: Sys
contentfulMetadata: ContentfulMetadata
linkedFrom: {
friendlyUserCollection: FriendlyUserCollection
entryCollection: EntryCollection
}
name: String
# ...
}
type Dog {
sys: Sys
contentfulMetadata: ContentfulMetadata
linkedFrom: {
friendlyUserCollection: FriendlyUserCollection
entryCollection: EntryCollection
}
name: String
# ...
}
type Asset {
sys: Sys
contentfulMetadata: ContentfulMetadata
linkedFrom: {
friendlyUserCollection: FriendlyUserCollection
entryCollection: EntryCollection
}
title: String
# ...
}
To retrieve names of all the cats and their owners you can then use the following query:
query {
catCollection {
items {
name
linkedFrom {
friendlyUserCollection {
items {
firstName
}
}
}
}
}
}
Notice that each linkedFrom
field also has a generic entryCollection
field. This field is always
present and allows you to query for linking entries of all types. If you don't have linkContentType
validations defined for your fields, entryCollection
is the only way to query for linking entries:
query {
catCollection {
items {
name
linkedFrom {
entryCollection {
items {
... on FriendlyUser {
firstName
}
}
}
}
}
}
}
By default the current locale
is used to search entry fields for links to the specific entry or asset.
To override this behavior the linkedFrom
field accepts an optional allowedLocales
argument.
Note that this does not change the locale of the entries in the collection.
Due to the way GraphQL API treats arrays you can omit brackets if you only need a single locale.
query {
catCollection {
items {
name
germanLinks: linkedFrom(allowedLocales: "de-DE") {
friendlyUserCollection {
items {
firstName
}
}
}
multilanguageLinks: linkedFrom(allowedLocales: ["de-DE", "en-US"]) {
friendlyUserCollection {
items {
firstName
}
}
}
}
}
}
Inline fragments
Since every GraphQL API type implements the Entry
interface, the content type of the entries can be linked without validation.
type Entry {
sys: Sys
contentfulMetadata: ContentfulMetadata
}
Link to single entry
The relationships are modeled by content type fields that
link to at most one entry. For example, each FriendlyUser
entry
has a manager
field that links to one entry of content type FriendlyUser
.
{
name: "Friendly User"
sys: {
id: "friendly-user",
...
},
fields: [
...,
{
id: "manager",
type: "Link",
linkType: "Entry",
}
]
}
This results in the following schema:
type FriendlyUser implements Entry {
sys: Sys
contentfulMetadata: ContentfulMetadata
linkedFrom: FriendlyUserLinkingCollections
manager: Entry
# ... other fields
}
To query the manager
field to be of type FriendlyUser
do the following query:
query {
friendlyUser(id: "hans") {
manager {
... on FriendlyUser {
# some user fields
}
}
}
}
Link to collection of entities
The relationships are modeled by content type fields that
link to a collection of entities. For example, each FriendlyUser
entry
has a managers
field that links to collection of entries.
{
name: "Friendly User"
sys: {
id: "friendly-user",
...
},
fields: [
...,
{
id: "managers",
type: "Array",
items: {
type: 'Link',
linkType: 'Entry'
}
}
]
}
This results in the following schema:
type FriendlyUser implements Entry {
sys: Sys
contentfulMetadata: ContentfulMetadata
linkedFrom: FriendlyUserLinkingCollections
managersCollection: FriendlyUserManagersCollection
# ... other fields
}
To only get the entries of type FriendlyUser
, you can do the following query:
query {
friendlyUser(id: "hans") {
managersCollection {
items {
... on FriendlyUser {
# some user fields
}
}
}
}
}
Entries
In addition to collections for entries of a specific content type, querying for the generic Entry
interface is supported
on the root Query
type.
type Query {
entryCollection(skip: Int, limit: Int): EntryCollection
}
The query above returns the following GraphQL types:
type Entry {
sys: Sys
contentfulMetadata: ContentfulMetadata
}
type EntryCollection {
skip: Int!
limit: Int!
total: Int!
items: [Entry]!
}
Example: Retrieve entries across content types using the root collection type
type Person {
sys: Sys
contentfulMetadata: ContentfulMetadata
surname: String
}
type Cat {
sys: Sys
contentfulMetadata: ContentfulMetadata
name: String
}
query {
entryCollection {
sys {
id
}
contentfulMetadata {
tags {
id
}
}
... on Cat {
name
}
... on Person {
surname
}
}
}
Assets
Assets in Contentful have a predefined schema function. This means that the type for any asset in the GraphQL schema follows the definition below:
type Asset {
sys: Sys
contentfulMetadata: ContentfulMetadata
linkedFrom: AssetLinkingCollections
title: String
description: String
contentType: String
fileName: String
url: String
size: Int
width: Int?
height: Int?
}
Assets are also supported as root queries. At present, there are two root queries for it: single asset and collection of assets.
type Query {
# ...
asset (id: String!): Asset
assetCollection(skip: Int, limit: Int): AssetCollection
}
The queries above return following GraphQL types:
type Asset {
sys: Sys
contentfulMetadata: ContentfulMetadata
linkedFrom: AssetLinkingCollections
title: String
description: String
contentType: String
fileName: String
url: String
size: Int
width: Int?
height: Int?
}
type AssetCollection {
skip: Int!
limit: Int!
total: Int!
items: [Asset]!
}
Unlike the CDA, the GraphQL Content API always serves asset URLs with a protocol, defaulting to HTTPS.
Image transformations
The GraphQL Content API exposes a set of image transformation options, such as cropping or resizing.
To request image transformations for an asset, you have to pass a transform
argument to its url
field.
For example:
{
asset(id: "KTsF62Q4gg60q6WCsWJw8") {
title
url(transform: {
width: 500,
height: 300,
resizeStrategy: FILL,
resizeFocus: BOTTOM,
backgroundColor: "rgb:321032",
cornerRadius: 100,
format: JPG,
quality: 90
})
}
}
Transformation options translate to query string parameters that are appended to the url
in the response.
The resulting URL endpoints to the transformed version of the image.
{
data: {
asset: {
title: "contentful-team",
url: "https://images.ctfassets.net/f8bqpb154z8p/4dgP2U7BeMuk0icguS4qGw/bc9431adf0b4a798b1aee97b2c56aa60/Contentful_team.png?w=500&h=300&q=90&fit=fill&f=bottom&r=100&bg=rgb%3A321032&fm=jpg"
}
}
}
Transformation options take no effect when the asset is not an image.
width
and height
Desired width and height of the image in pixels. Accept values between 1
and 4000
.
If not defined, default to the original image width and height.
quality
Desired quality of the image. Used for PNG8
, JPG
, JPG_PROGRESSIVE
and WEBP
formats.
Accepts percentage values, between 1
and 100
.
cornerRadius
Desired corner radius in pixels.
Results in an image with rounded corners (pass -1
for a full circle/ellipse).
If not defined, defaults to 0
. Uses desired background color as padding color,
unless the format is JPG
or JPG_PROGRESSIVE
and resize strategy is PAD
, then defaults to white.
resizeStrategy
Desired resize strategy. Accepts the following enum type values:
FIT
(default) resizes the image to fit into the specified dimensions.PAD
resizes the image to the specified dimensions, padding the image if needed. Uses desired background color as padding color.FILL
resizes the image to the specified dimensions, cropping the image if needed.SCALE
resizes the image to the specified dimensions, changing the original aspect ratio if needed.CROP
crops a part of the original image to fit into the specified dimensions.THUMB
creates a thumbnail from the image focusing on the focus area
resizeFocus
Desired resize focus area. Accepts the following enum type values:
CENTER
(default)TOP
,RIGHT
,LEFT
,BOTTOM
.TOP_RIGHT
,TOP_LEFT
,BOTTOM_RIGHT
,BOTTOM_LEFT
.FACE
- focuses on the largest face.FACES
- focuses on the area containing all the faces.
It has no effect when used with FIT
or SCALE
resize strategy.
backgroundColor
Desired background color, used with corner radius or PAD
resize strategy.
Accepts RGB values in rgb:ffffff
format.
If not defined, defaults to transparent (for PNG
, PNG8
and WEBP
) or white (for JPG
and JPG_PROGRESSIVE
).
format
Desired image format. Accepts the following enum
values:
JPG
JPG_PROGRESSIVE
Progressive JPG format stores multiple passes of an image in progressively higher detail. While a progressive image is loading, the viewer will first see a lower quality pixelated version, which will gradually improve in detail, until the image is fully downloaded. This displays the image as early as possible in order to maintain the layout as designed.PNG
PNG8
8-bit PNG images support up to 256 colors and weigh less than the standard 24-bit PNG equivalent. The 8-bit PNG format is mostly used for simple images, such as icons or logos.WEBP
If not defined, defaults to the original image format.
Locations
Locations are represented as types with the properties lat
and lon
.
The GraphQL type looks like:
type Location {
lat: Float
lon: Float
}
Collections can be filtered on fields with Location
type by applying supported filters.
Rich text
Rich text fields are represented as types with two properties:
json
that exposes the actualRichText
field value in a JSON formatlinks
that allows you to deeply query various types of referenced entities
For example, if the content type Article
has a RichText
field text
, the following types are generated:
type Article {
text: ArticleText
}
type ArticleText {
json: JSON!,
links: ArticleTextLinks!
}
type ArticleTextLinks {
entries: ArticleTextEntries!,
assets: ArticleTextAssets!
resources: ArticleTextResourceLinks!
}
type ArticleTextEntries {
inline: [Entry]!
block: [Entry]!
hyperlink: [Entry]!
}
type ArticleTextAssets {
block: [Asset]!
hyperlink: [Asset]!
}
type ArticleTextResourceLinks {
block: [ResourceLink!]!
}
Following is an example of a query for a RichText
field value and linked entities:
query {
article(id: "some-article") {
text {
json
links {
assets {
block {
title
url
}
}
entries {
inline {
sys {
id
}
... on Person {
name
age
}
}
}
resources {
block {
sys {
type
urn
linkType
}
}
}
}
}
}
}
Never
The Never
field type is used with the Functions feature.
This type is assigned to the _data
suffixed field when an error occurred during schema generation.
For example, when the remote schema cannot be fetched, the _data
fields depending on that schema will have the Never
type. Field selections on a Never
field will always return null
, and the error information can be found in the errors
array of the response.
Note that your Contentful schema can be fetched as it is and will not be impacted by any errors caused by external references.
Collection fields
Collections of entries and assets are exposed through collection fields in the root query object and in one-to-many relationship fields. For example:
type FriendlyUserCollection {
skip: Int!
limit: Int!
total: Int!
items: [FriendlyUser]!
}
input FriendlyUserFilter {
# ... field based filters
}
type Query {
# ...
friendlyUserCollection(
skip: Int
limit: Int,
where: FriendlyUserFilter
): FriendlyUserCollection
}
Arguments
The following optional arguments are available when querying a collection:
Argument | Type | Description |
---|---|---|
skip |
Number | zero-indexed offset in the collection from which items are fetched. The default is 0 |
limit |
Number | maximum number of items to fetch. The default is 100 and the maximum is 1000 |
where |
InputType | filter specifications to apply on the collection query. For more information see the Collection Filters section |
order |
InputType | order specifications to apply on the collection query. For more information see the Collection Order section. |
preview |
Boolean | when set to true the field will be resolved with non published content. The default is false |
locale |
String | locale for the collection items. If not set the default locale is used. |
Return value
The value returned from a collection field contains the meta fields skip
,
limit
and, total
and the requested items in the items
field. The skip
and limit
fields corresponds to respective input arguments. The total
fields
contains the total number of items in that collection.
Collection Filters
The GraphQL Content API allows users to specify filters on root collection queries.
Collections could be filtered by different fields or combination of fields that contain collection items. There are general and type specific filters:
Filter | Postfix | Field type |
---|---|---|
equal | <any scalar> |
|
not equal | _not | <any scalar> |
exists | _exists | <any> |
contains | _contains | String, RichText |
does not contain | _not_contains | String, RichText |
greater than | _gt | Number, Date |
greater or equals | _gte | Number, Date |
less than | _lt | Number, Date |
less or equals | _lte | Number, Date |
in given list | _in | String, Number, Date |
not in given list | _not_in | String, Number, Date |
within circle | _within_circle | Location |
within rectangle | _within_rectangle | Location |
contains all | _contains_all | Array |
contains some | _contains_some | Array |
contains none | _contains_none | Array |
For each content type the schema defines an input type to filter entries of that content type.
For example, for the type FriendlyUser
structured in the following way:
type FriendlyUser {
sys: Sys
name: String
age: Integer
}
The schema defines the following filter input type:
input FriendlyUserFilter {
sys: SysFilter
contentfulMetadata: ContentfulMetadataFilter
name: String
name_not: String
name_exists: Boolean
name_contains: String
# ... more name filters
age: Number
age_gt: Number
age_lt: Number
# ... more age filters
AND: [FriendlyUserFilter]
OR: [FriendlyUserFilter]
}
Filter inputs can be passed to collection queries of their corresponding type to filter out mutations and the result set.
For example, to find all FriendlyUser
s whose name is "Frank" or "Francine" and who are older than 30 years, write the following query:
query {
friendlyUserCollection(where: {
AND: [
{
OR: [
{ name: "Frank" },
{ name: "Francine" }
]
},
{ age_gt: 30 }
],
}) {
name
age
}
}
Limitations
It is not possible to filter on fields of Type Object
or RichText
.
There's an exemption in the case of the ContentfulMetadata
type.
_contains
filter is case insensitive and must be at least 2 characters long to
work. The _contains
filter is analogous to the [match]
filter in the REST API
content. Check the
documentation
of the [match]
operator for more information about the details of full-text
search in contentful.
For performance reasons it is not recommended to use the
_contains
filter when searching for slugs or text IDs.
Please use the equality search instead.
Filter generation
Filter input types are derived from the content model, just like the output types. For each content type, one filter input type is derived. The user can pass it to the corresponding root collection query.
Each filter input type has the sys
, AND
, and OR
fields as well as
additional field type specific filters for every field.
Name of the filter input type is derived from the output type by appending Filter
to it.
Logical connectives
Each filter input type has two special fields AND
and OR
. These fields are used to logically combine filters.
If multiple fields are specified on a filter, they get connected with an implicit AND
:
query {
friendlyUserCollection(where: {
OR: [
{ name: "Hans" },
{ name: "Joe" }
]
age_gte: 30,
age_lte: 40
}) { name }
}
And result in the following equivalent query:
query {
friendlyUserCollection(where: {
AND: [
OR: [
{ name: "Hans" },
{ name: "Joe" }
],
{ age_gte: 30 },
{ age_lte: 40 }
]
}) { name }
}
Both queries return all the friendly users between the age of 30 to 40 and are named either Hans or Joe.
Filters by field type
For each field in a content type a set of filter fields is added to the content type’s filter input type. The type of filters is determined by the field type.
Symbol
and Text
GraphQL Content API does not distinguish between Symbol
and Text
types and
generates the same filters for both.
For example, if the content type FriendlyUser
has a Symbol
field name
, the following types are generated:
type FriendlyUser {
# ... other fields
name: String
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field is equal to the given value
name: String
# Matches if the field is not equal to the given value
name_not: String
# Matches if the field exists
name_exists: Boolean
# Matches if the field value equal one of the given values
name_in: [String]
# Matches if the field value does not equal any of the given values
name_not_in: [String]
# Matches if given value is a substring of the the field value
name_contains: String
# Matches if given value is not a substring of the the field value
name_not_contains: String
}
Number
and Integer
Filter names for Integer
and Number
types are same. They only differ in the input types for values.
For Integer
fields the value type is Int
, whereas for Number
fields the type is Float
.
For example, if the content type FriendlyUser
has an Integer
field age
, the following types are generated:
type FriendlyUser {
# ... other fields
age: Int
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field is equal to the given value
age: Int
# Matches if the field is not equal to the given value
age_not: Int
# Matches if the field exists
age_exists: Boolean
# Matches if the field value equal one of the given values
age_in: [Int]
# Matches if the field value does not equal any of the given values
age_not_in: [Int]
# Matches if the field value is strictly smaller than the given value
age_lt: Int
# Matches if the field value is smaller than or equal to the given value
age_lte: Int
# Matches if the field value is strictly greater than the given value
age_gt: Int
# Matches if the field value is greater than or equal to the given value
age_gte: Int
}
Boolean
Boolean
filter accepts values of type Boolean
and could be used only on fields with type Boolean
.
For example, if the content type FriendlyUser
has an Boolean
field employed
, the following types are generated:
type FriendlyUser {
# ... other fields
employed: Boolean
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field is equal to the given value
employed: Boolean
# Matches if the field is not equal to the given value
employed_not: Boolean
# Matches if the field exists
employed_exists: Boolean
}
Date
For the fields with type Date
the value types are DateTime
.
The value for filter should be provided full DateTime value
in ISO-8601 format eg yyyy-mm-ddThh:mm:ss:sssZ
.
For example, if the content type FriendlyUser
has an DateTime
field birthday
,
the following types are generated:
type FriendlyUser {
# ... other fields
birthday: DateTime
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field is equal to the given value
birthday: DateTime
# Matches if the field is not equal to the given value
birthday_not: DateTime
# Matches if the field exists
birthday_exists: Boolean
# Matches if the field value equal one of the given values
birthday_in: [DateTime]
# Matches if the field value does not equal any of the given values
birthday_not_in: [DateTime]
# Matches if the field value is strictly smaller than the given value
birthday_lt: DateTime
# Matches if the field value is smaller than or equal to the given value
birthday_lte: DateTime
# Matches if the field value is strictly greater than the given value
birthday_gt: DateTime
# Matches if the field value is greater than or equal to the given value
birthday_gte: DateTime
}
Location
For fields with type Location
the value types are either Circle
or Rectangle
.
The Circle
scalar type has the following format:
{
lat: 10.11,
lon: 10.11,
radius: 10,
}
where lat
and lon
are coordinates of the center of the circle and radius
its radius in kilometers.
The Rectangle
scalar type has the following format:
{
topLeftLat: 40,
topLeftLon: 13.35,
bottomRightLat: 41,
bottomRightLon: 14.36
}
where topLeftLat
with topLeftLon
are the coordinates of the top left corner of the rectangle, and bottomRightLat
with bottomRightLon
are the coordinates of the bottom right corner of the rectangle.
For example, if the content type FriendlyUser
has an Location
field place
,
the following types are generated:
type FriendlyUser {
# ... other fields
place: Location
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the position is inside the given circle
place_within_circle: Circle
# Matches if the position is inside the given rectangle
place_within_rectangle: Rectangle
}
Array
For Array fields with the value type String. The value for the filter should be an array of string values.
For example, if the content type FriendlyUser
has an Array
field nicknames
,
the following types are generated:
type FriendlyUser {
# ... other fields
nicknames: [String]
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field array contains *all* items provided to the filter
nicknames_contains_all: [String]
# Matches if the field array contains at least one item provided to the filter
nicknames_contains_some: [String]
# Matches if the field array doesn't contain any item provided to the filter
nicknames_contains_none: [String]
}
Link
For Link fields with a single linkContentType
validation. Filtering depth is limited to one level of relationships.
The collection filter input type has a property corresponding to the field name. The type of this input filter property
has filters for all the linked fields (without nested Link
fields).
type FriendlyUser {
sys: Sys
firstbornChild: Child
# ... other fields
}
type Child {
name: String
}
input FriendlyUserFilter {
sys: SysFilter
contentfulMetadata: ContentfulMetadataFilter
firstbornChild: FriendlyUserFirstbornChildFilter
# ... more filters
}
input FriendlyUserFirstbornChildFilter {
sys: SysFilter
contentfulMetadata: ContentfulMetadataFilter
name: String
name_not: String
name_exists: Boolean
name_contains: String
# ... more name filters
}
sys filters
Every filter input type has a sys
property. The type of the sys
filter property
is the statically defined SysFilter
type.
input FriendlyUserFilter {
sys: SysFilter
# ... other fields
}
input SysFilter {
id: String
id_not: String
id_in: [String]
id_not_in: [String]
id_contains: String
id_not_contains: String
}
Similar to other field filters the SysFilter
input type is generated from the Sys
output type. For each field in the Sys
type, a set of
corresponding filters are added to SysFilter
.
The following is an example of a query language for a list of entries by IDs:
query {
friendlyUserCollection(where: {
sys: {
id_in: ["id1", "id2"]
}
}) { sys { id } }
}
contentfulMetadata filters
Every filter input type has a contentfulMetadata
property. The type of the contentfulMetadata
filter property
is the statically defined ContentfulMetadataFilter
type.
input EntryCollectionFilter {
sys: SysFilter
contentfulMetadata: ContentfulMetadataFilter
}
input ContentfulMetadataFilter {
tags_exists: Boolean
tags: ContentfulMetadataTagsFilter
}
input ContentfulMetadataTagsFilter {
id_contains_some: [String!]
id_contains_none: [String!]
id_contains_all: [String!]
}
The ContentfulMetadataFilter
input type is generated from the tags
field in the ContentfulMetadata
type and its id
subfield in the ContentfulTag
type.
The following is an example of a query for a list of entries across content types by tag presence and tag IDs:
query {
entryCollection(where: {
contentfulMetadata: {
tags_exists: true
tags: {
id_contains_some: ["tagId1", "tagId2"]
}
}
}) {
sys {
id
}
contentfulMetadata {
tags {
id
}
}
}
}
Nested collection filters
You can filter a multi reference field collection if the field contains a validation rule that makes it accept only specific content types.
If the reference field only accepts a single content type, then you can filter by any field on that content type.
query {
friendlyUserCollection {
items {
firstName
catCollection(where: {name: "foorbar"}) {
items {
name
}
}
}
}
}
On the other hand, if the reference field accepts multiple content types, then you can filter by any field that is common across all of those content types.
A field is considered common if it has the same apiName
(field id) and type on all content types. Consider you have the following content types:
Cat
- field Name:
Cat Name
, field Id:name
, type: text - field Name:
Legs
, field Id:legs
, type: number - field Name:
Lives Left
, field id:livesLeftOfNine
, type: number
- field Name:
Dog
- field Name:
Dog Name
, field Id:name
, type: text - field Name:
Legs
, field Id:legs
, type: boolean - field Name:
Likes Walks
, field id:likesWalks
, type: boolean
- field Name:
Person
- field Name:
Pets
, field Id:pets
, type: Reference, validations: Accept only specified entry types: Cat, Dog
- field Name:
On Person
you will be able to query petsCollection
by the fields that have the same field id and type on Cat
and Dog
.
Per our content types definition above: the only common field is name
(same field id name
and type text
on both collections).
The field legs
will not be a common field as it's type differs across the content types.
query {
friendlyUserCollection {
items {
firstName
petsCollection(where: {name: "foorbar"}) {
items {
__typename
... on Cat {
name
numberOfLivesLeft
}
... on Dog {
name
likesGoingForWalks
}
}
}
}
}
}
The petsCollection
can be filtered by the fields common to both Cat
and Dog
types, such as name
. It cannot be filtered by fields specific to any one content type, such as livesLeftOfNine
or likesGoingForWalks
.
Link Filtering
You can filter on Links within Entries. The same logic applies as for nested filtering: your Content Model must include validations specifying the Content Type (or types) for the Link.
For example, the following schema can be generated for a content model that contains a Blog Post
content type, with the Title
and Content
fields as strings and a Link
to an entry with a validation specifying an Author
:
type BlogPost {
sys: Sys
title: String
content: String
author: Author
}
type Author {
sys: Sys
name: String
}
You can filter on any fields of the author
type. For example:
query {
blogPostCollection {
items {
title
content
author(where: {name: "Blog Post Author"}) {
name
}
}
}
}
If there is a match, then the author will be returned. Otherwise, you will receive a null value. All of the same filters that are available on collections are available on this single link level.
Collection Order
The GraphQL Content API allows users to specify the fields and direction to sort on root collection queries.
For example, for the type FriendlyUser
structured in the following way:
type FriendlyUser {
sys: Sys
name: String
age: Integer
}
The schema defines the following order input enum type:
enum FriendlyUserOrder {
name_ASC
name_DESC
age_ASC
age_DESC
sys_id_ASC
sys_id_DESC
}
Order enum values can be passed to collection queries of their corresponding type to sort the result set.
For example, to find the oldest FriendlyUser
, write the following query:
query {
friendlyUserCollection(order: [age_DESC], limit: 1) {
items {
name
}
}
}
Collections can be sorted by multiple fields, each of them with a direction information.
For example, to order FriendlyUser
s by their age (descending) first and for items with same age it should sort by name (ascending), write the following query:
query {
friendlyUserCollection(order: [age_DESC, name_ASC]) {
items {
name
age
}
}
}
You can order collections in linkedFrom
.
query {
catCollection {
items {
name
linkedFrom {
friendlyUserCollection(order: [age_DESC, name_ASC]) {
items {
firstName
}
}
}
}
}
}
entryCollection
field.
query {
catCollection {
items {
name
linkedFrom {
friendlyUserCollection(order: [age_DESC, name_ASC]) {
items {
firstName
}
entryCollection {
__typename
}
}
}
}
}
}
Limitations
It is not possible to order on fields of Type Link
, Text
, Location
, Object
, or RichText
.
Resource Links
Resource Links are part of the Cross-space references feature that allows you to link content across multiple spaces. It mainly uses ResourceLink
links as a way to represent a relationship between entities from different spaces.
ResourceLink
links are represented as a sys
object containing urn
, linkType
and type
:
Property | Description |
---|---|
sys.linkType |
Represents what kind of entity this resource links to. For cross-space entries the value is Contentful:Entry . |
sys.type |
The type of Link. ResourceLink is the default for cross-space resources. |
sys.urn |
The location of the resource. A CRN to a Contentful environment entity. |
As they are part of another space, resolving cross-space linked entities requires a special header to be passed in each request named x-contentful-resource-resolution
.
Extra header for cross-space resolution
The x-contentful-resource-resolution
header is a base64 encoded JSON object containing key-value pairs of spaceID/API Key. The plain JSON used to create the header should have the following shape:
{
"spaces": {
"someSpaceId": "<cda-token>",
"anotherSpaceId": "<cda-token>"
}
}
That then needs to be stringified and encoded to base64. You can use JSON.stringify
and btoa
(JavaScript) to properly convert the JSON object to a stringified encoded version of it.
Here is a full example in JavaScript:
const extraTokens = {
"spaces": {
"IdToR3s0lv3": "ND63YKcYBe335RWDnIuzv...",
"4n0th3rSp4c3": "UuVe6icuBuXv..."
}
}
// Converts object to string and uses base64 to encode the string
window.btoa(JSON.stringify(extraTokens)) // eyJzcGFjZXMiOnsiSWRUb1I[...]=
The value can then be passed to the x-contentful-resource-resolution
header as-is.
Capabilities
The
locale
query parameter is propagated to all extra spaces present in the new header.Publishing new content in any of the extra spaces will cause the cache to be purged on every request that included that space ID.
Cross-space queries support preview requests if the preview token is provided.
Limitations
Up to 4 spaces to be resolved in a single request.
Only 3 extra space tokens are supported. You can make a single API call that resolves up to 4 spaces at the same time: 3 extra spaces and the entries from the space ID in the initial request.
Only the first level of cross-space references is resolved from the original space ID in the URL.
The
Authorization
header is still required for every request and it should enable access to the main space ID in the URL.Errors from the extra space tokens will be returned in the
errors
property of the response.Using the
x-contentful-resource-resolution
header will also consume the Rate Limiting from the space IDs present in it when the request is uncached.
For more information, see the Resource Links FAQs.
Default ordering
If you don't pass an explicit order value the returned collection items will be ordered
descending by publication timestamp (sys.updatedAt
) and ascending by ID
(sys.id
). This means that recently published items will appear closer to
the top, and for those with the same publication timestamp the order will be
based on the item IDs.
Note that the above default ordering only apples to top level collections. Nested collections are ordered in the same order they were linked to the parent entry.
linkedFrom
does not have any default ordering or sorting.
Single resource fields
When you want to fetch just one resource of a given type, you can use the single
resource fields. As explained in the types section, the name
of this fields is the camelcased version of the content type from which they
derive or asset
.
type Query {
contentModule (id: "introduction") {
...
}
asset (id: "my-picture") {
...
}
}
Arguments
The following arguments are available when querying a single resource:
Argument | Type | Required | Description |
---|---|---|---|
id |
String | true |
The id of the resource you want to fetch |
preview |
Boolean | false |
when set to true the field will be resolved with non published content. The default is false |
locale |
String | false |
locale for the resource. If not set, the default locale is used. |
Automatic Persisted Queries
You can use this feature to double the 8kb
limit on the query size to 16kb
if you are a customer on our Premium plan and above, plus to cache the query in Contentful to decrease the payload delivered through the network.
- First, you have to send the query and a
sha256Hash
value of that query:
curl --location --request POST 'https://graphql.contentful.com/content/v1/spaces/{SPACE}/environments/{ENVIRONMENT}' \
--header 'Authorization: Bearer {TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
"query": "{__typename}",
"extensions": { "persistedQuery": { "sha256Hash": "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38", "version": 1 } }
}'
- Then, you can only send the hash to execute the cached query:
curl --location --request POST 'https://graphql.contentful.com/content/v1/spaces/{SPACE}/environments/{ENVIRONMENT}' \
--header 'Authorization: Bearer {TOKEN}' \
--header 'Content-Type: application/json' \
--data-raw '{
"extensions": { "persistedQuery": { "sha256Hash": "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38", "version": 1 } }
}'
Taxonomy
Taxonomy concepts
IDs associated with entries and assets can be resolved under the contentfulMetadata
field.
query {
articleCollection {
items {
contentfulMetadata {
concepts {
id
}
}
}
}
}
You can also filter entries queries by concept IDs that have been referenced directly. To filter the entries, you need to know the concept ID. It can be found inside the URL path in the web app.
To find the concept ID:
- Open the Organization settings & subscriptions.
- Navigate to the Taxonomy manager tab.
- Click on a concept. The ID is the final URL segment.
query {
articleCollection(
where: {
contentfulMetadata: {
concepts_exists: true
concepts: {
id_contains_some: ["conceptId_3", "conceptId_4"]
id_contains_none: ["conceptId_1", "conceptId_2"]
id_contains_all: ["conceptId_0", "conceptId_00"]
}
}
}
)
items {
title
}
}
Additionally, you can use the descendants
filter to return any entries which have Taxonomy concepts that reference the supplied concept IDs or their children.
query {
articleCollection(
where: {
contentfulMetadata: {
concepts: {
descendants: {
id_contains_some: ["conceptId_3", "conceptId_4"]
id_contains_none: ["conceptId_1", "conceptId_2"]
id_contains_all: ["conceptId_0", "conceptId_00"]
}
}
}
}
)
items {
title
}
}
Ordering Nested Collections
You can order any collection if it contains a many reference field with a validation rule that accepts only entries from a single content type.
query {
friendlyUserCollection {
items {
firstName
catCollection(order: [name_ASC]) {
items {
name
}
}
}
}
}
Resource Links
Resource Links are part of the Cross-space references feature set that allows you to link content across multiple spaces. It mainly uses ResourceLink
links as a way to represent a relationship between entities from different spaces.
ResourceLink
links are represented in the GraphQL Content API as a sys
object containing urn
and linkType
:
Property | Description |
---|---|
sys.linkType |
Represents what kind of entity this resource links to. For cross-space entries the value is Contentful:Entry . |
sys.urn |
The location of the resource. A CRN to a Contentful environment entity. |
As they are part of another space, resolving cross-space linked entities requires a special header to be passed in each request named x-contentful-resource-resolution
.
Extra header for cross-space resolution
The x-contentful-resource-resolution
header is a base64 encoded JSON object containing key-value pairs of spaceId/API Key. The plain JSON used to create the header should have the following shape:
{
"spaces": {
"someSpaceId": "<cda-token>",
"anotherSpaceId": "<cda-token>"
}
}
That then needs to be stringified and encoded to base64. You can use JSON.stringify
and btoa
(JavaScript) to properly convert the JSON object to a stringified encoded version of it.
Here is a full example in JavaScript:
const extraTokens = {
spaces: {
IdToR3s0lv3: 'ND63YKcYBe335RWDnIuzv...',
'4n0th3rSp4c3': 'UuVe6icuBuXv...',
},
}
// Converts object to string and uses base64 to encode the string
window.btoa(JSON.stringify(extraTokens)) // eyJzcGFjZXMiOnsiSWRUb1I[...]=
The value can then be passed to the x-contentful-resource-resolution
header as-is.
Usage
Cross space references can be resolved through the use of a special node
field for content types which have a linked reference from another space. Fields of the referenced content type are accessed with an inline fragment with a type name in the following format: {CONTENT_TYPE}_{SPACE}_{ENVIRONMENT}
.
query {
authorCollection {
items {
writings {
node {
... on novel_4n0th3rSp4c3_Master {
title
}
}
# ResourceLink properties
sys {
linkType
urn
}
}
}
}
}
Limitations
Only
3
extra space tokens are supported. You can make a single API call that resolves up to4
spaces at the same time:3
extra spaces and the entries from the space Id in the initial request.The
Authorization
header is still required for every request and it should enable access to the main space Id in the URL.Errors from the extra space tokens will be returned in the
errors
property of the response.Using the new header will also consume the Rate Limiting from the space Ids present in it when the request is uncached.
No Advanced Caching support
For more information, see the Resource Links FAQs.
Custom external references
The Custom external references feature (formerly known as Third party orchestration) enables you to resolve content referenced from any third party system using the Contentful GraphQL API.
Some of our marketplace apps already support Custom external references out-of-the-box, such as Shopify, commercetools and Cloudinary. For those that don’t, you can create your own app with Functions to enable the Custom external references capability.
Functions
Functions connect to external systems, fetch additional content and enrich
the response of the GraphQL request issued through Contentful's GraphQL API. With functions, you can use _data
suffix in your GraphQL query
and stitch remote schemas together with your Contentful schema. The _data
prefix can be used only when the field is annotated to be resolved in delivery with an app.
Once you enable the Resolve content on delivery
checkbox on your field settings and you configure your field with a custom app, you can resolve remote content using GraphQL API.
If your function has an error caused by the remote schema, query or response, you will receive an UNRESOLVABLE_RESOURCE_LINK error. If the schema generation was not successful, the _data
suffixed field will be of type Never.
Exploring the schema with GraphiQL
You can explore and inspect the schema of a space using the GraphiQL, an in-browser GraphQL IDE.
To open GraphiQL server visit the
https://graphql.contentful.com/content/v1/spaces/{SPACE}/explore?access_token={CDA_TOKEN}
URL in your browser. You must provide the CDA_TOKEN
as a query parameter.
GraphQL Errors
The GraphQL Content API responses via GitHub contains errors that occur during the different phases of a request (authentication, validation, schema generation and execution) dependencies. Among these errors there can also be other internal system errors.
The errors returned by the GraphQL API follow the GraphQL error spec via GitHub.
There is an additional contentful
object in the extensions
error property with information relevant to the failed
request to facilitate debugging and fixing problems. The contentful
object contains the following properties:
code
: unique error identifier.requestId
: unique request identifier.details
: optional object with details about a specific kind of error.
The following is an example of such a response from the API deployment:
{
data: { // query data: optional, might be presented in case of partial response queries
...
},
errors: [{
message: 'Query execution error. Query too complex to be executed in allocated resources', // Human readable error message
locations: [{line: 4, column: 17}],
path: ['too', 'many', 'db_ops'],
extensions: {
contentful: {
code: 'RESOURCES_EXHAUSTED', // text error code
requestId: 'xxx' // id of current request
}
}
}]
}
List of known errors:
Category | HTTP status code | Message | Is partial* |
---|---|---|---|
Authentication | 401 | ACCESS_TOKEN_MISSING |
no |
Authentication | 401 | ACCESS_TOKEN_INVALID |
no |
Schema generation | 422 | COLLIDING_TYPE_NAMES |
no |
Schema generation | 422 | COLLIDING_FIELD_NAMES |
no |
Schema generation | 422 | RESERVED_FIELD_NAME |
no |
Validation | 400 | UNKNOWN_ENVIRONMENT |
no |
Validation | 400 | UNKNOWN_SPACE |
no |
Validation | 400 | MISSING_QUERY |
no |
Validation | 400 | QUERY_TOO_BIG |
no |
Validation | 400 | INVALID_QUERY_FORMAT |
no |
Validation | 404 | PersistedQueryNotFound |
no |
Validation | 400 | PersistedQueryMismatch |
no |
Validation | 400 | INVALID_VARIABLES_FORMAT |
no |
Validation | 400 | TOO_COMPLEX_QUERY |
no |
Validation | 400 | QUERY_OPERATION_NAME_MISMATCH |
no |
Query execution | 200 | UNKNOWN_LOCALE |
yes |
Query execution | 200 | UNRESOLVABLE_LINK |
yes |
Query execution | 200 | UNEXPECTED_LINKED_CONTENT_TYPE |
yes |
Query execution | 200 | UNRESOLVABLE_RESOURCE_LINK |
yes |
Query execution | 200 | RESOURCES_EXHAUSTED |
yes |
System errors | 200 | INTERNAL_SERVER_ERROR |
yes |
System errors | 500 | INTERNAL_SERVER_ERROR |
no |
System errors | 429 | RATE_LIMIT_EXCEEDED |
no |
Is partial indicates whether for given error partial data response is possible.
For more information, read our tutorials that cover frontend and backend technologies so you can implement GraphQL queries into your application, including languages JavaScript, Android and iOS (requires Apollo).
GraphQL Errors Explained
COLLIDING_TYPE_NAMES
The COLLIDING_TYPE_NAMES
error is returned when one or more content type IDs are converted to the same GraphQL type name. For more information about this error, see the Colliding type names section.
Example
errors: [{
message: "Schema generation failed. Type name generated for the content types 'A_car', 'a_car_' would be the same for all of them: 'ACar'",
extensions: {
contentful: {
code: 'COLLIDING_TYPE_NAMES',
details: {
collidingContentTypeIds: ['A_car', 'a_car_'],
resultingTypeName: 'ACar',
},
documentationUrl: ‘xxxxxx/colliding-type-names
requestId: 'xxx'
}
}
}]
}
Solution
To prevent this error, make sure the content type IDs in your space environment cannot result in the same GraphQL type name. You can either enter two unique random IDs in the creation phase, or provide two distinct names that wouldn’t be converted to the same ID or GraphQL type name later on. For more information on how schemas and the type names are generated for your GraphQL schema, see the Schema generation section.
To fix this error, recreate one of the content types that have colliding IDs, making sure the new ID won’t collide with the second content type ID. You can also use the scripted approach described in the Scripting migrations with the Contentful CLI guide.
COLLIDING_TYPE_NAMES during query execution
We dynamically create the types for GraphQL values based off of their names. As a result, users can inadvertently create naming collisions.
The following example is a common scenario of how a naming collision can occur:
- Create the following content types:
BlogPost
,BlogPostContent
andBlogPostMoreContent
. - Add a reference field called
content
to yourBlogPost
content type, and allow it to link toBlogPostContent
andBlogPostMoreContent
. - Create an entry of type
BlogPost
with its content field linking to an entry of typeBlogPostMoreContent
. - Query the
BlogPost entry
including the linked entry. A generic error message is returned expecting only entries of typeBlogPostContent
instead ofBlogPostMoreContent
.
Here is a breakdwon of what is actually happening:
When generating a BlogPostContent
, we create an API-wide collection called BlogPostContentCollection
for querying purposes. However, when generating the content field on a BlogPost
, we also need to create a collection to enable querying. Unfortunately, this creates a name collision issue as both collections have the same name, but different types.
This conflict can cause various issues in the codebase. In some cases, we are able to prevent schema generation. However, sometimes this occurs at query execution.
To fix this, determine what fields are causing a collision and rename one of the conflicting fields.
COLLIDING_FIELD_NAMES
The COLLIDING_FIELD_NAMES
error is returned when several field IDs from the same content type are transformed into the same GraphQL field name.
Example
errors: [
{
message: "Schema generation failed. Field name 'firstName' generated for the field 'first_name' in the content type 'brand' collides with an already existing field.",
extensions: {
contentful: {
code: "COLLIDING_FIELD_NAMES",
details: {
fieldApiName: "first_name",
contentTypeId: "brand",
fieldName: "firstName"
},
documentationUrl: ‘xxxxxx/colliding-field-names
requestId: 'xxx'
}
}
}
]
}
Solution
To prevent this error, make sure the field IDs you’re using on each content type cannot result in the same GraphQL field name. To fix this error, change the ID of one of the colliding fields in question using the web app or the Content Management API.
RESERVED_FIELD_NAME
The RESERVED_FIELD_NAME
error is returned when a field ID is transformed into a reserved GraphQL field name. Reserved field names are sys
, linkedFrom
and contentfulMetadata
.
Example
errors: [{
message: "Schema generation failed. Field name 'linkedFrom' generated for the field 'linked_from' in the content type 'blog' is reserved.",
extensions: {
contentful: {
code: 'RESERVED_FIELD_NAME',
details: {
contentTypeId: 'blog',
fieldId: 'sys'
},
documentationUrl: ‘xxxxxx/reserved-field-names'
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, change the field ID to a value that does not collide with any of the reserved names using the web app or the Content Management API.
UNKNOWN_ENVIRONMENT
The UNKNOWN_ENVIRONMNET
error is returned when the requested environment does not exist or when the provided authentication token does not allow access to the specified environment.
Example
errors: [{
message: 'Query cannot be executed. Requested environment does not exist in the space',
extensions: {
contentful: {
code: 'UNKNOWN_ENVIRONMENT',
details: {
availableEnvironments: ['master', 'qa']
},
documentationUrl: ‘xxxxxx/unknown-environment'
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error you can:
request an environment from the list of environments that are already enabled for your content delivery token, or
adjust the token so that it has access to the environment you want to use in your query.
For more information on how authentication to the Content Delivery API and Content Preview API works and how you can configure them, see the Authentication section of the API reference.
UNKNOWN_SPACE
The UNKNOWN_SPACE
error is returned when the space ID included in the URL is incorrect.
Example
errors: [{
message: 'Query cannot be executed. The space could not be found.',
extensions: {
contentful: {
code: 'UNKNOWN_SPACE',
details: {
message: 'Check if the space id in the URL is correct.'
},
documentationUrl: ‘xxxxxx/unknown-space'
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error you can:
- request an environment from the list of environments that are already enabled for your content delivery token, or
- adjust the token so that it has access to the environment you want to use in your query.
For more information on how authentication to the Content Delivery API and Content Preview API works and how you can configure them, see the Authentication section of the API reference.
MISSING_QUERY
The MISSING_QUERY
error is returned when the POST
request does not contain a payload or when the GET
request does not contain the following query parameter: query
.
Example
errors: [{
message: 'Query cannot be executed. The request does not include a query neither in the body nor in the query string',
extensions: {
contentful: {
code: 'MISSING_QUERY',
documentationUrl: ‘xxxxxx/missing-query'
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, include a query in the body of a POST
request or a query
query parameter in the GET
request.
QUERY_TOO_BIG
The QUERY_TOO_BIG
error is returned when the query exceeds the maximum allowed size.
Example
errors: [{
message: `Query cannot be executed. The maximum allowed size for a query is XXX bytes but it was YYY bytes`,
extensions: {
contentful: {
code: 'QUERY_TOO_BIG',
documentationUrl: ‘xxxxxx/query-too-big'
querySizeInBytes: XXX,
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, divide the query into smaller parts to get the information you need in multiple smaller queries.
INVALID_QUERY_FORMAT
The INVALID_QUERY_FORMAT
error is returned when the query is not of type string
.
Example
errors: [{
message: "Query cannot be executed. The query is not a string",
extensions: {
contentful: {
code: 'INVALID_QUERY_FORMAT',
documentationUrl: ‘xxxxxx/invalid-query-format'
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, make sure the query passed in the request is of type string
.
INVALID_VARIABLES_FORMAT
The INVALID_VARIABLES_FORMAT
error is returned when the variables included in the request are not a valid JSON object.
Example
errors: [{
message: "Query cannot be executed. The request variables are not a JSON object",
extensions: {
contentful: {
code: 'INVALID_VARIABLES_FORMAT',
documentationUrl: ‘xxxxxx/invalid-variables-format'
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, check the integrity of the variables sent and make sure the JSON object is valid.
PersistedQueryNotFound
The PersistedQueryNotFound
error is returned when you send a hash for a query that is not cached in our server.
Example
errors: [{
message: "PersistedQueryNotFound",
extensions: {
contentful: {
code: 'PERSISTED_QUERY_NOT_FOUND',
documentationUrl: ‘xxxxxx/persisted-query-not-found'
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, make sure you cached the query first by sending the hash and the query in a previous request.
PersistedQueryMismatch
The PersistedQueryMismatch
error is returned when the sha256Hash
does not match the expected query hash.
Example
errors: [{
message: "PersistedQueryMismatch",
extensions: {
contentful: {
code: 'PERSISTED_QUERY_MISMATCH',
documentationUrl: ‘xxxxxx/persisted-query-mismatch'
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, make sure you hashed the query using the sha256Hash
algorithm.
TOO_COMPLEX_QUERY
The TOO_COMPLEX_QUERY
error is returned when the calculated query complexity exceeds the maximum complexity allowed.
Example
errors: [{
message: `Query cannot be executed. The maximum allowed complexity for a query is 10000 but it was 20000. Simplify the query e.g. by setting lower limits for collections.`,
extensions: {
contentful: {
code: 'TOO_COMPLEX_QUERY',
details: {
cost: 10000,
maximumCost: 20000
},
documentationUrl: ‘xxxxxx/too-complex-query’
requestId: 'xxx'
}
}
}]
}
Solution
To avoid this issue, simplify the query complexity by setting a lower limit in the GraphQL query. You can also limit the depth of the query. For reference fields, it’s recommended to set a limit on the number of allowed links in the content modeling section. If there is a lower number than the default 1000, it will be used to calculate the overall complexity instead.
Examples of actions to optimize a query
- Make sure all the collections queried have a limit set on them:
Query to avoid | Optimized query |
---|---|
query { |
query { |
- Lower the limits on nested collections in the query to significantly lower the resulting cost:
Query to avoid | Optimized query |
---|---|
query { |
query { |
- If you know how many entries can be in a specific collection, set the limit to that number or lower:
Query to avoid | Optimized query |
---|---|
query { |
query { |
- If you have the
linkedFrom
field and you know the exact number of entries you are linking to, set the limit to that number:
Query to avoid | Optimized query |
---|---|
query { |
query { |
- If the query is too deep, fetch the IDs of a nested collection and use a separate query for that collection:
Query to avoid | Optimized query |
---|---|
query { |
query {Get all the IDs in teacher.sys.id and use another query:query($teacherIds: [String]) { |
QUERY_OPERATION_NAME_MISMATCH
The QUERY_OPERATION_NAME_MISMATCH
error is returned when a GraphQL request is received without a valid or matching operation name. The server cannot determine which operation to execute based on the provided operation name.
The error message includes the received operation name and the available operation names found in the query.
Example
"errors": [
{
"message": "Could not determine what operation to execute, received 'blogPostCollectionQuery3' but found 'blogPostCollectionQuery1, blogPostCollectionQuery2'",
"extensions": {
"contentful": {
"code": "QUERY_OPERATION_NAME_MISMATCH",
"requestId": "xxx"
}
}
}
]
}
Possible Causes:
- The operation name provided in the GraphQL request does not match any of the operation names defined in the query.
- The GraphQL query does not contain any operation names.
Solution
- Ensure that the operation name provided in the request is spelled correctly and matches one of the operation names defined in the query.
- If the GraphQL query does not contain any operation names, make sure to include the operation name when sending the request.
UNKNOWN_LOCALE
The UNKNOWN_LOCALE
error is returned when the requested locale does not exist.
Example
data: {
pet: null
},
errors: [{
message: "Query execution error. Requested locale 'de-DE' does not exist in the space",
locations: [{ line: 0, column: 0 }],
path: ['pet'],
extensions: {
contentful: {
code: 'UNKNOWN_LOCALE',
details: {
availableLocaleCodes: ['en-US', 'es-ES']
},
documentationUrl: ‘xxxxxx/unknown-locale'
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, request one of the available locale codes returned in the error details. For more information about editing a locale, see the Localization with Contentful tutorial.
UNRESOLVABLE_LINK
The UNRESOLVABLE_LINK
error is returned when a link cannot be resolved because the target entity does not exist or it is not published.
NOTES:
When a link cannot be resolved, a
null
value is returned on that field.When a link in an array cannot be resolved, a
null
value on its position is returned.For each link that cannot be resolved, an error object with the details is sent with the response.
To distinguish between single entity links and array links, pay attention to the type in the GraphQL schema and the actual GraphQL response.
Examples
{
data: {
pet: null
},
errors: [{
message: "Query execution error. Link to entry 'my-dog' on field 'pet' within type 'Blog' cannot be resolved",
locations: [{line: x, column: y}], // whatever
path: ['pet'],
extensions: {
contentful: {
code: 'UNRESOLVABLE_LINK',
details: {
type: 'FriendlyUser',
field: 'pet',
linkType: 'entry',
linkId: 'my-dog'
},
documentationUrl: ‘xxxxxx/unresolvable-link',
requestId: 'xxx'
}
}
}]
}
// Array link
// Note that we return one error per unresolvable link, almost identical, except by the `path`
{
data: {
pets: [
{ name: 'fido' },
null,
{ name: 'scuby' },
null
]
},
errors: [{
message: "Query execution error. Link to entry 'my-dog' on field 'pets' within type 'Blog' cannot be resolved",
locations: [{line: x, column: y}], // whatever
path: ['pets', 1],
extensions: {
contentful: {
code: 'UNRESOLVABLE_LINK',
details: {
type: 'FriendlyUser',
field: 'pets',
linkType: 'entry',
linkId: 'my-dog'
},
documentationUrl: ‘xxxxxx/unresolvable-link',
requestId: 'xxx'
}
}
},
{
message: "Query execution error. Link to entry 'my-dog' on field 'pets' within type 'Blog' cannot be resolved",
locations: [{line: x, column: y}], // whatever
path: ['pets', 2],
extensions: {
contentful: {
code: 'UNRESOLVABLE_LINK',
details: {
type: 'FriendlyUser',
field: 'pets',
linkType: 'entry',
linkId: 'my-dog'
},
documentationUrl: ‘xxxxxx/unresolvable-link',
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, adjust your query to only request entities that exist and are published. Additionally, you can handle this specific error gracefully in your application.
Skip unresolvable links
You can skip over unresolvable links by filtering where the sys.id_exists
is true
.
NOTE: To use the filter, you must have a validation rule set on the many reference field that makes it only accept one content type.
query {
friendlyUserCollection {
items {
firstName
catCollection(limit: 100, where:{sys:{id_exists:true}}) {
items {
name
}
}
}
}
}
UNEXPECTED_LINKED_CONTENT_TYPE
The UNEXPECTED_LINKED_CONTENT_TYPE
error is returned when the linked entry has an unexpected content type linked to it in the validations. This happens when a validation in a field is changed to disallow a specific content type that was previously allowed, while entries with links to that content type still exist.
Example
{
message:
"Query execution error. Link from entry 'blog-1' to entry 'Tom' on field 'externalAuthor' within type 'Blog' returned an unexpected content type",
locations: [{ line: 4, column: 13 }],
path: ['blog', 'externalAuthor'],
extensions: {
contentful: {
code: 'UNEXPECTED_LINKED_CONTENT_TYPE',
details: {
type: 'Blog',
field: 'externalAuthor',
entryId: 'Tom',
contentType: 'person',
permittedContentTypes: ['someOtherContentType'],
linkingEntryId: 'blog-1',
},
documentationUrl: ‘xxxxxx/unexpected-linked-content-type',
requestId: someRequestId,
},
},
},
]
Solution
To fix this error, you can remove the links to entries to content types that aren’t allowed anymore, or adjust the allowed content types in the linked entry.
RESOURCES_EXHAUSTED
The RESOURCES_EXHAUSTED
error is returned when the GraphQL query has used more resources for its execution than allowed.
Example
data: {
too: {
name: 'Josh',
age: 22,
many: {
db_ops: null,
}
}
},
errors: [{
message: 'Query execution error. Query too complex to be executed in allocated resources',
locations: [{ line: 4, column: 17 }], // Whatever
path: ['too', 'many', 'db_ops'],
extensions: {
contentful: {
code: 'RESOURCES_EXHAUSTED',
documentationUrl: ‘xxxxxx/unresolvable-link',
requestId: 'xxx'
}
}
}]
}
Solution
To fix this error, split the query into multiple simple queries.
UNRESOLVABLE_RESOURCE_LINK
The UNRESOLVABLE_RESOURCE_LINK
error is returned when a Custom external references or Functions query fails.
Example
{
"message": "Query execution error. 'vendorId' link cannot be resolved",
"extensions": {
"contentful": {
"code": "UNRESOLVABLE_RESOURCE_LINK",
"documentationUrl": "xxxxxx/unresolvable-resource-link",
"requestId": "xxx",
"details": {
"app": "vendorId"
}
}
},
"locations": [
{ "line": 4, "column": 17 }
],
"path": ["contentTypeId", "fieldId"]
}
]
Solution
To fix this error, you need to check your Third party data query and your entry that is linked to your app.