www.contentful.com Open in urlscan Pro
2a05:d014:58f:6202::1f4  Public Scan

Submitted URL: http://graphql-contentful.lululemon.com/
Effective URL: https://www.contentful.com/developers/docs/references/graphql/
Submission Tags: @phish_report
Submission: On May 09 via api from FI — Scanned from FI

Form analysis 0 forms found in the DOM

Text Content

Developers
 * Developer portal
 * Documentation
 * Changelog
 * Blog
 * Pricing

Select...Developer portalDocumentationChangelogBlogPricing
SIGN UPLOGIN

ConceptsTutorialsPlatformsAPI
referenceExtensibilityWebhooksInfrastructureExperiencesComposeTools and Plugins
 * Introduction
   * Basic API Information
   * HTTP Methods
   * Authentication
   * API rate limits
   * Query complexity limits
   * Query size limits
   * Rich Text
   * Tags
   * Previewing content
 * Reference
   * Locale handling
   * Schema generation
     * Types
     * Reserved type names
     * Fields
     * Schema generation failure
     * Sys field
     * ContentfulMetadata field
     * Modeling relationships
     * One-to-one single-type relationships
     * One-to-one multi-type relationships
     * One-to-many single-type relationships
     * One-to-many multi-type relationships
     * Inline fragments
     * Link to single entry
     * Link to collection of entities
     * Entries
     * Assets
     * Locations
     * Rich text
     * Never
   * Collection fields
     * Arguments
     * Return value
   * Collection Filters
     * Limitations
     * Filter generation
     * Logical connectives
     * Filters by field type
     * sys filters
     * contentfulMetadata filters
     * Nested collection filters
   * Link Filtering
   * Collection Order
     * Limitations
   * Single resource fields
     * Arguments
   * Automatic Persisted Queries
   * Ordering Nested Collections
   * External references
     * Functions
   * Exploring the schema with GraphiQL
   * GraphQL Errors
     * GraphQL Errors Explained

Documentation / API reference / GraphQL Content API


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.

Note: For EU data residency customers, the Base URL is
https://graphql.eu.contentful.com.


BASIC API INFORMATION

API Base URL https://graphql.contentful.com
This is a read-only API


BASIC API INFORMATION



The Contentful GraphQL Content API is available at:

Copyhttps://graphql.contentful.com/content/v1/spaces/{SPACE}

It is also available for specific environments at:

Copyhttps://graphql.contentful.com/content/v1/spaces/{SPACE}/environments/{ENVIRONMENT}

Disclaimer: GraphQL Content API is available on all spaces for customers on
current pricing plans. If you are on a legacy plan, contact Customer Support to
upgrade.


HTTP METHODS



The GraphQL Content API supports both GET and POST methods.

This is the query used in both examples below:

Copyquery($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".

Copycurl -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.

Copycurl -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

CopyHTTP/1.1 429
X-Contentful-RateLimit-Reset: 1

Meaning: wait 1 second before making more requests.


QUERY COMPLEXITY LIMITS


Disclaimer: The default complexity limit for collections is 100. The query
complexity is calculated as the maximum number of entries and assets a query can
potentially return.

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

Copyquery {
  lessonCollection(limit: 20) {
    items {
      title
    }
  }
}

The query above can return up to 20 Lessons. The query complexity is 20.

Example 2

Copyquery {
  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

Copyquery {
  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.

Note: You can use automatic persisted queries to bypass this limit if you are a
customer on our Premium plan and above.


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

Copyquery{
  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

Copyquery {
  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:

Copyquery {
  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:

Copyquery {
  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:

Copyquery {
  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.

Copyquery {
  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:

Copyquery {
  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:

Copy{
  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.

Copytype 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.

Copy{
  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:

Copytype 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 or linkedFrom
   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.

Copytype 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.

Copytype 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.

Copy{
  name: "Friendly User"
  sys: {
    id: "friendly-user",
    ...
  },
  fields: [
    ...,
    {
      id: "manager",
      type: "Link",
      linkType: "Entry",
      validations: [{ linkContentType: ["friendlyUser"] }]
    }
  ]
}

This results in the following schema:

Copytype 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.

Copy{
  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:

Copytype 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.

Copy{
  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.

Copytype 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.

Copy{
  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:

Copytype 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:

Copy{
  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:

Copytype 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:

Copyquery {
  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:

Copyquery {
  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.

Copyquery {
  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.

Copy  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.

Copy{
  name: "Friendly User"
  sys: {
    id: "friendly-user",
    ...
  },
  fields: [
    ...,
    {
      id: "manager",
      type: "Link",
      linkType: "Entry",
    }
  ]
}

This results in the following schema:

Copytype 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:

Copyquery {
  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.

Copy{
  name: "Friendly User"
  sys: {
    id: "friendly-user",
    ...
  },
  fields: [
    ...,
    {
      id: "managers",
      type: "Array",
      items: {
        type: 'Link',
        linkType: 'Entry'
      }
    }
  ]
}

This results in the following schema:

Copytype 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:

Copyquery {
  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.

Copytype Query {
  entryCollection(skip: Int, limit: Int): EntryCollection
}

The query above returns the following GraphQL types:

Copytype 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

Copytype Person {
  sys: Sys
  contentfulMetadata: ContentfulMetadata
  surname: String
}

Copytype Cat {
  sys: Sys
  contentfulMetadata: ContentfulMetadata
  name: String
}

Copyquery {
  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:

Copytype 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.

Copytype Query {
  # ...
  asset (id: String!): Asset
  assetCollection(skip: Int, limit: Int): AssetCollection
}

The queries above return following GraphQL types:

Copytype 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:

Copy{
  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.

Copy{
  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:

Copytype 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 actual RichText field value in a JSON format

 * links 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:

Copytype 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:

Copyquery {
  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:

Copytype 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:

Copytype FriendlyUser {
  sys: Sys
  name: String
  age: Integer
}

The schema defines the following filter input type:

Copyinput 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 FriendlyUsers whose name is "Frank" or "Francine" and
who are older than 30 years, write the following query:

Copyquery {
  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:

Copyquery {
  friendlyUserCollection(where: {
    OR: [
      { name: "Hans" },
      { name: "Joe" }
    ]
    age_gte: 30,
    age_lte: 40
  }) { name }
}

And result in the following equivalent query:

Copyquery {
  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:

Copytype 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:

Copytype 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:

Copytype 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:

Copytype 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:

Copy{
  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:

Copy{
  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:

Copytype 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:

Copytype 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).

Copytype 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.

Copyinput 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:

Copyquery {
  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.

Copyinput 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:

Copyquery {
  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.

Copyquery {
  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

 * 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

 * Person
   
   * field Name: Pets, field Id: pets, type: Reference, validations: Accept only
     specified entry types: Cat, Dog

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.

Copyquery {
  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.

Note: When you filter a reference field which accepts more than one content
type, the complexity of your query increases by the number of content types the
field can accept.



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:

Copytype 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:

Copyquery {
  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:

Copytype FriendlyUser {
  sys: Sys
  name: String
  age: Integer
}

The schema defines the following order input enum type:

Copyenum 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:

Copyquery {
  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 FriendlyUsers by their age (descending) first and for
items with same age it should sort by name (ascending), write the following
query:

Copyquery {
  friendlyUserCollection(order: [age_DESC, name_ASC]) {
    items {
      name
      age
    }
  }
}

You can order collections in linkedFrom.

Copyquery {
  catCollection {
    items {
      name
      linkedFrom {
        friendlyUserCollection(order: [age_DESC, name_ASC]) {
          items {
            firstName
          }
        }
      }
    }
  }
}

NOTE: You cannot order the entryCollection field.

Copyquery {
  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.

Note: When using `allowedLocales`, the order argument that you have passed will
not be applied to the fallback values, which might make the result seem to be
unordered.


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.

Important: 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.

Copytype 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 bypass the 8kb limit on the query size 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:

Copycurl --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:

Copycurl --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 } }
}'

Note: If you sent a wrong hash you will get a `PersistedQueryMismatch` error. If
you sent a hash without caching the query first, you will get a
`PersistedQueryNotFound` error.



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.

Copyquery {
  friendlyUserCollection {
    items {
      firstName
      catCollection(order: [name_ASC]) {
        items {
          name
        }
      }
    }
  }
}




EXTERNAL REFERENCES



The 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 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 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.

Note: This feature is currently available through our Early Access Program
(EAP).

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:

Copy{
  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

Copy  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:

 1. Create the following content types: BlogPost, BlogPostContent and
    BlogPostMoreContent.
 2. Add a reference field called content to your BlogPost content type, and
    allow it to link to BlogPostContent and BlogPostMoreContent.
 3. Create an entry of type BlogPost with its content field linking to an entry
    of type BlogPostMoreContent.
 4. Query the BlogPost entry including the linked entry. A generic error message
    is returned expecting only entries of type BlogPostContent instead of
    BlogPostMoreContent.

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

Copy  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

Copy  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

Copy  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

Copy  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

Copy  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

Copy  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

Copy  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

Copy  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

Copy  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

Copy  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

Disclaimer: The default complexity limit for collections is 100. The query
complexity is calculated as the maximum number of entries and assets a query can
potentially return.

The TOO_COMPLEX_QUERY error is returned when the calculated query complexity
exceeds the maximum complexity allowed.

EXAMPLE

Copy  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 {
  lessonCollection {
    items {
      title
    }
  }
}

query {
  lessonCollection(limit: 20) {
    items {
      title
    }
  }
}

 * Lower the limits on nested collections in the query to significantly lower
   the resulting cost:

Query to avoid Optimized query

query {
  lessonCollection(limit: 200) {
    items {
      title
      imageCollection {
        title
        url
      }
    }
  }
}

query {
  lessonCollection(limit: 20) {
    items {
      title
      imageCollection(limit: 10) {
        title
        url
      }
    }
  }
}

 * 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 {
  lessonCollection(limit: 200) {
    items {
      title
      imageCollection(limit: 100) {
        title
        url
      }
    }
  }
}
# if imageCollection contains only 50 entries
# then it’s better to lower the limit to 50.

query {
  lessonCollection(limit: 200) {
    items {
      title
      imageCollection(limit: 50) {
        title
        url
      }
    }
  }
}

 * 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 {
  catCollection(limit: 20) {
    items {
      name
      linkedFrom {
        entryCollection {
          items {
            ... on FriendlyUser {
              firstName
            }
          }
        }
      }
    }
  }
}
# if you know that the number
# of entries linked from is 5
# set the limit to 5

query {
  catCollection(limit: 20) {
    items {
      name
      linkedFrom {
        entryCollection(limit: 5) {
          items {
            ... on FriendlyUser {
              firstName
            }
          }
        }
      }
    }
  }
}

 * 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 {
  lessonCollection(limit: 200) {
    items {
      title
      teacher {
        name
        primaryLessonsCollection(limit: 100) {
          items {
            title
          }
        }
      }
    }
  }
}

query {
  lessonCollection(limit: 200) {
    items {
      title
      teacher {
        sys {
          id
        }
      }
    }
  }
}

Get all the IDs in teacher.sys.id and use another query:

query($teacherIds: [String]) {
  teacherCollection(where: {
    sys: { id_in: $teacherIds } }
  ) {
    items {
      name
      primaryLessonsCollection(limit: 100) {
        items {
          title
        }
      }
    }
  }
}


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

Copy    "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

Copy  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

Copy{
  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.

Copyquery {
  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

Copy       {
         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

Copy  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 an External references or
Functions query fails.

EXAMPLE

Copy  {
    "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.




ALL TOPICS

Learn more at Contentful.com


CONCEPTS

 * API basics
 * App Framework
 * Domain model
 * Data model
 * Entry and asset links
 * Images
 * Content localization through locales
 * Sync API
 * Multiple environments
 * Environment Aliases
 * Environment support for Cross-space references
 * Environments and environment aliases best practices
 * Webhooks
 * Filter API results with relational queries
 * What is rich text?
 * External references
 * Continuous integration and deployment pipelines


TUTORIALS

 * General
 * CLI
 * JavaScript
 * PHP
 * Android
 * iOS
 * Java
 * Python
 * Ruby
 * .NET


PLATFORMS

 * JavaScript
 * PHP
 * Android
 * iOS
 * Java
 * Python
 * Ruby
 * .NET


API REFERENCE

 * Content Delivery API
 * Content Management API
 * Content Preview API
 * Images API
 * GraphQL Content API
 * User Management API
 * SCIM API
 * Authentication
 * Errors
 * HTTP details
 * App SDK reference


EXTENSIBILITY

 * App Framework
 * Field editors
 * OAuth


WEBHOOKS

 * Overview
 * Content events
 * Action events
 * Configuring a webhook
 * List webhooks in a space
 * Activity log
 * Webhook Templates
 * Request Verification


INFRASTRUCTURE

 * Multi-region delivery infrastructure (MRDI)
 * Advanced caching
 * EU data residency


EXPERIENCES

 * What are Experiences?
 * Set up Experiences SDK
 * Register custom components
 * Component definition schema
 * Built-in styles
 * Design tokens
 * Data structures
 * Error handling
 * Image optimization
 * Using Experiences with NextJS


COMPOSE

 * What is Compose?
 * Customizable Compose content model
 * Page types
 * Known Limitations - Compose
 * Upgrade to customizable Compose content model
 * Content model best practices for Compose
 * Extending and customizing Compose
 * Roles and Permissions for Compose
 * CLI tools and Compose
 * Building a website with Compose in Next.js
 * Frequently Asked Questions
 * Documentation for editors
 * Legacy content model


TOOLS AND PLUGINS

 * Space management
 * Static site generators
 * Automation and developer workflows
 * Command-line interface (CLI)
 * AI Content Type Generator


LEARN MORE


SupportGet started


WEB APP

 * Contentful overview
   
 * Modeling basics
   
 * Creating a digital lookbook
   
 * Localization
   
 * Versioning
   
 * Roles and permissions
   


ADVANCED

 * Webhooks
   
 * CMS as code
   
 * Headless & Decoupled CMS
   


MORE

 * Changelog
 * API Changes
 * Technical limits
 * Code of Conduct
 * Support
   
 * Stack Overflow
   

• All Systems Operational