This page explains how to:
- Formulate a GraphQL API request
- Apply scopes
- Determine query complexity
- Achieve Reference Expansion
- Query project-specific dynamic data such as Custom Fields and Attributes
Get started
Interactive GraphQL console
Application of scopes
Use case | GraphQL service | Scope |
---|---|---|
query for a particular resource | Query.{resourceType} | view_{resourceType}s:{projectKey} |
query for resources of a certain type | Query.{resourceType}s | view_{resourceType}s:{projectKey} |
create a resource of a certain type | Mutation.create{resourceType} | manage_{resourceType}s:{projectKey} |
update a particular resource | Mutation.update{resourceType} | manage_{resourceType}s:{projectKey} |
delete a particular resource | Mutation.delete{resourceType} | manage_{resourceType}s:{projectKey} |
manage_products:{projectKey}
is required for updating a Product with the Mutation.updateProduct
service. The view_products:{projectKey}
scope would not be sufficient for this.view_published_products:{projectKey}
scope can be used by the Query.products
service to retrieve data in masterData.current
, but not in masterData.staged
. The same applies for the Query.productProjectionSearch
service that only returns data with this scope when the staged
parameter is set to false
in such queries.Query.inStore
requires view_{resourceType}s:{projectKey}:{storeKey}
.Representations
GraphQLRequest
The query, operation name, and variables that are sent to the GraphQL API.
query ​String​ | String representation of the Source Text of the Document that is specified in the Language section of the GraphQL specification. |
operationName ​String​ | Name of the operation, if you defined several operations in query . |
variables ​ | JSON object that contains key-value pairs in which the keys are variable names and the values are variable values. |
{
"query": "query getProductByKey($productKey: String!) { product(key: $productKey) { id version }}",
"operationName": "getProductByKey",
"variables": {
"productKey": "a-product-key"
}
}
GraphQLVariablesMap
The variables that the GraphQL query uses.
// ​Any string parameter matching this regular expression​ | JSON object that contains key-value pairs in which the keys are variable names and the values are variable values. |
{
"productKey": "a-product-key"
}
GraphQLResponse
error
is present in the response only if the GraphQL query was unsuccessful.data ​Any​ | JSON object that contains the results of a GraphQL query. |
errors ​Array of GraphQLError​ | Errors that the GraphQL query returns. |
{
"data": {
"product": {
"id": "35d33405-2d39-4528-b195-fa3ab6beb927",
"version": 2
}
}
}
Query GraphQL
GraphQL uses HTTP POST requests to both query and mutate data.
Execute a GraphQL request.
view_products:{projectKey}
region String ​ | Region in which the Project is hosted. |
projectKey String ​ | key of the Project. |
application/json
application/json
curl https://api.{region}.commercetools.com/{projectKey}/graphql -i \
--header "Authorization: Bearer ${BEARER_TOKEN}" \
--header 'Content-Type: application/json' \
--data-binary @- << DATA
{
"query" : "query getProductByKey($productKey: String!) { product(key: $productKey) { id version }}",
"operationName" : "getProductByKey",
"variables" : {
"productKey" : "a-product-key"
}
}
DATA
{
"data": {
"product": {
"id": "35d33405-2d39-4528-b195-fa3ab6beb927",
"version": 2
}
}
}
Errors
GraphQLError
Contains an error message, the location of the code that caused the error, and other information to help you correct the error.
message ​String​ | Detailed description of the error explaining the root cause of the problem and suggesting how to correct the error. |
locations ​Array of GraphQLErrorLocation​ | Location within your query where the error occurred. |
path ​Array of Any​ | Query fields listed in order from the root of the query response up to the field in which the error occurred. path is displayed in the response only if an error is associated with a particular field in the query result. |
extensions ​ | Dictionary with additional information where applicable. |
{
"message": "Object 35d33405-2d39-4528-b195-fa3ab6beb927 has a different version than expected. Expected: 1 - Actual: 2.",
"path": [
"deleteProduct"
],
"locations": [
{
"line": 2,
"column": 3
}
],
"extensions": {
"code": "ConcurrentModification",
"currentVersion": 2
}
}
GraphQLErrorLocation
Represents the location within your query where the error occurred.
line ​Int​ | Line number of the query where the error occurred. |
column ​Int​ | Position in line where the error occurred. |
GraphQLErrorObject
Represents a single error.
code ​String​ | One of the error codes that is listed on the Errors page. |
// ​Any string parameter matching this regular expression​ | Error-specific additional fields. |
Query Attributes, Custom Objects, and Custom Fields
Product Attributes, Custom Objects, and Custom Fields contain Project-specific dynamic data that can be accessed by using raw GraphQL fields.
Retrieve Product Attributes
value
field reflect the data type that is used by the Product Attribute. For more information, see AttributeType. You must determine the data type yourself.Example query and response for raw Product Attributes:
query {
product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
masterData {
current {
variants {
...variantFields
}
}
}
}
}
fragment variantFields on ProductVariant {
sku
attributesRaw {
name
value
}
}
{
"data": {
"product": {
"masterData": {
"current": {
"variants": [
{
"sku": "M0E20000000E218",
"attributesRaw": [
{
"name": "productSupported",
"value": true
},
{
"name": "supportContact",
"value": {
"en": "english@example.com",
"de": "german@example.com"
}
}
]
}
]
}
}
}
}
}
Retrieve Custom Fields
value
field reflect the data type that is used by the Custom Field. For more information, see FieldType. You must determine the data type yourself.Example query and response for raw Custom Fields:
{
product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
masterData {
current {
variants {
prices {
...customFields
}
}
}
}
}
}
fragment customFields on ProductPrice {
custom {
customFieldsRaw {
name
value
}
}
}
{
"data": {
"product": {
"masterData": {
"current": {
"variants": [
{
"prices": [
{
"custom": {
"customFieldsRaw": [
{
"name": "kiloPrice",
"value": {
"type": "centPrecision",
"currencyCode": "EUR",
"centAmount": 95,
"fractionDigits": 2
}
}
]
}
}
]
}
]
}
}
}
}
}
Create Product Attributes, Custom Fields, and Custom Objects
value
field should be a string containing escaped JSON.value
field on ProductAttributeInput
:"{\"type\": \"centPrecision\", \"currencyCode\": \"USD\", \"centAmount\": 1000, \"fractionDigits\": 2}"
"\"yellow\""
value
field on CustomFieldInput
:"[\"This is a string\", \"This is another string\"]"
"{\"id\": \"b911b62d-353a-4388-93ee-8d488d9af962\", \"typeId\": \"product\"}"
value
field on CustomObjectDraft
:"{ \"stringField\": \"myVal\", \"numberField\": 123, \"boolField\": false, \"nestedObject\": { \"nestedObjectKey\": \"anotherValue\" }, \"dateField\": \"2018-10-12T14:00:00.000Z\" }"
Use Product Projection Search
productProjectionSearch
query.Fetch all Product Variants
productProjectionSearch
query provides the following query fields to fetch the Master Variant or the additional Product Variants of a Product Projection separately or all together.masterVariant
- Fetches the Master Variant only.variants
- Fetches only the Product Variants in addition to the Master Variant.allVariants
- Fetches all Product Variants including the Master Variant.
query {
productProjectionSearch {
results {
masterVariant {
key
}
variants {
id
}
allVariants {
sku
}
}
}
}
Fetch only matching Product Variants
productProjectionSearch
query, you can control whether or not the response contains only the Product Variants that match the search query.
To accomplish this, set markMatchingVariants: true
, and set the onlyMatching
flag in the variants
or allVariants
field to true
.The flag behaves as follows:
onlyMatching: true
- Returns only the matching Product Variants.onlyMatching: false
- Returns only the non-matching Product Variants.- no flag - Returns all Product Variants.
onlyMatching
flag without setting markMatchingVariants
to true
, the results will be empty even though matching Product Variants may exist.query {
productProjectionSearch(
markMatchingVariants: true
queryFilters: {
model: { value: { path: "variants.price.centAmount", values: ["1299"] } }
}
) {
results {
key
allVariants(onlyMatching: true) {
sku
}
}
count
}
}
Check if resources exist
exists
field in your query. This will optimize the query and result in a shorter response time.true
if there is at least one result matching the query condition, or false
if there are none.query {
# As the quotation marks are within quotation marks, they must be escaped
products(where: "productType(id=\"55e43a8a-b130-4ea3-9d90-4fd97bf90ab9\")") {
exists
}
}
{
"data": {
"products": {
"exists": true
}
}
}
Reference Expansion
By convention, the GraphQL API offers two fields for each expandable reference:
<fieldName>Ref
- Fetches the Reference or KeyReference to the resource only (lower query complexity).<fieldName>
- Fetches the expanded resource that is referenced (higher query complexity).
Returnsnull
if the referenced resource is not found.
<fieldName>Ref
to get a better performance on your query.For example, to retrieve the number of child Categories for a specific Category and the identifiers for its ancestors:
{
category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
children {
id
}
ancestors {
id
}
}
}
{
"data": {
"category": {
"children": [
{
"id": "7900ab4b-c01c-4e73-8f10-557b84de55f5"
},
{
"id": "93aa3372-310f-4fa7-8ab2-986036382e4f"
},
{
"id": "0938dbd3-766e-48c2-b86b-31a3a3d820da"
}
],
"ancestors": [
{
"id": "1fbfdc4b-b6c7-4f06-9db4-cbd4179f2a17"
}
]
}
}
}
children
array. The identifiers for ancestors are listed in the ancestors
field.childCount
field. Also, if you only need the identifiers for the ancestors, it is better to use the ancestorsRef
field.{
category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
childCount
ancestorsRef {
id
}
}
}
{
"data": {
"category": {
"childCount": 3,
"ancestorsRef": [
{
"id": "1fbfdc4b-b6c7-4f06-9db4-cbd4179f2a17"
}
]
}
}
}
Custom Fields BETA
value
of the referenced Custom Object in the same query.query {
category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
custom {
customFieldsRaw(includeNames: ["categoryCustom"]) {
referencedResource {
... on CustomObject {
value
}
}
}
}
}
}
{
"data": {
"category": {
"custom": {
"customFieldsRaw": [
{
"referencedResource": {
"value": {
"extraCategoryData": "This is extra Category data"
}
}
}
]
}
}
}
}
Product Attributes BETA
referencedResource
(for single references) and referencedResourceSet
(for sets of references) under attributesRaw
for allVariants
or masterVariant
:{
product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
masterData {
current {
allVariants {
attributesRaw {
referencedResource {
## If a referenced Product exists, return its name, SKUs, and key
... on Product {
masterData {
current {
slug(locale: "en")
}
}
skus
key
}
## If a referenced ProductType exists, return the Attributes names and ProductType name
... on ProductTypeDefinition {
attributeDefinitions {
results {
name
}
}
name
}
}
referencedResourceSet {
## If a set of referenced Products exists, return their names, SKUs, and keys
... on Product {
masterData {
current {
slug(locale: "en")
}
}
skus
key
}
## If a set of referenced ProductTypes exists, return their Attribute names and ProductType names
... on ProductTypeDefinition {
attributeDefinitions {
results {
name
}
}
name
}
}
}
}
}
}
}
}
Product Search Attributes BETA
referencedResource
(for single references) and referencedResourceSet
(for sets of references) under attributesRaw
for masterVariant
:{
productProjectionSearch(staged: true) {
results {
masterVariant {
attributesRaw(
includeNames: "{includedAttributes}"
excludeNames: "{excludedAttributes}"
) {
name
value
referencedResource {
id
... on Product {
skus
}
}
referencedResourceSet {
id
... on Product {
skus
}
}
}
}
}
}
}
Query complexity
You can fetch a lot of information in a single HTTP request using GraphQL. This is really helpful to avoid parsing unused fields, and the unnecessary network overhead by reducing the number of requests. At the same time, it is important to remember that a single query can potentially generate a lot of database operations. Hence, you cannot assume that the response time for a query increases linear with the number of fields in the query.
The GraphQL schema defines a "cost" per field, which you can display using following options:
-
Inspecting the
x-graphql-query-complexity
response header and its value. -
Using the GraphQL Explorer query profiler to measure the impact.
QueryComplexityLimitExceeded
20 000
. In such cases, queries return a QueryComplexityLimitExceeded error code with the HTTP status code 400
.code ​String​ | "QueryComplexityLimitExceeded" |
message ​String​ | |
// ​Any string parameter matching this regular expression​ | Error-specific additional fields. |
Public beta functionalities BETA
createdBy
andlastModifiedBy
onVersioned
MultiBuyLineItemsTarget
andMultiBuyCustomLineItemsTarget
onCartDiscount
stores
onCartDiscount
- everything related to
MyCart
,MyOrder
,MyPayment
,MyProfile
,MyShoppingList
,MyBusinessUnit
,MyQuote
,MyQuoteRequest
NestedTypes
onProductType
referencedResource
andreferencedResourceSet