Get started with GraphQL
GraphQL is an open-source query language that allows you to pull specified data from multiple sources with one call. For more information about GraphQL, visit graphql.org.
Learn more about how to use GraphQL with Composable Commerce in our self-paced GraphQL module.
Objectives of this guide
By the end of this guide you will have:
Placeholder values
Example code in this getting started guide uses placeholders that should be replaced with these values:
Placeholder | Replace with | From |
---|---|---|
{projectKey} | project_key | your API Client |
{region} | your Region | Hosts |
${BEARER_TOKEN} | your access token | Make your first API call |
Query your Project with GraphQL
The Composable Commerce GraphQL Explorer is available for evaluating and trying out commands.
GraphQL API requests can be executed using a POST call to the /graphql
endpoint.
Use the GraphQL Explorer
To explore the GraphQL API, you can use the GraphQL Explorer in the Merchant Center.
- Log in to the Merchant Center.
- Go to Settings > Developer settings > GraphQL Explorer.
- Enter GraphQL queries in the left panel.
Use autocomplete
When using the GraphQL Explorer, press ctrl
+space
to view a list of valid entries. Use the up/down arrow keys to navigate the list.
Use an API request
This example code shows how to return basic Project information.
POST https://api.{region}.commercetools.com/{projectKey}/graphql/Authorization: Bearer ${BEARER_TOKEN}{"query": "query ReturnProjectInformation { project { key createdAt }}"}
{"data": {"project": {"key": "{projectKey}","createdAt": "2022-01-23T18:02:58.542Z"}}}
Structure GraphQL requests
The structure of GraphQL calls vary based on whether you want to query existing data, create entities, or update existing entities.
Query existing entities
Querying existing entities within your Project uses query
. A name can be included to describe the call.
# Query existing dataquery ReturnCustomers{}
Add an endpoint
In this example, customers
targets all of our Customers. To target a single Customer, use customer
.
query ReturnCustomers{# Access the Customers endpointcustomers{}}
query ReturnASingleCustomer {# Access the Customer endpointcustomer() {}}
Add query parameters
When querying an endpoint such as customers
(where all Customers are targeted) these query parameters can be added based on your requirements.
Parameter | Action | Example use |
---|---|---|
where | Only returns entities that match the Query Predicate. Quotation marks within quotation marks must be escaped. | where: "firstName=\"John\"" |
sort | Changes the order of the returned entities. | sort: "lastName asc" |
limit | The maximum number of results to return. The default value is 20. | limit: 5 |
offset | Used for skipping results. The default value is 0. | offset: 1 |
When querying an endpoint like customer
(where a single Customer is targeted) you must enter a unique identifier for the entity (usually its id
or key
).
Query parameters must be enclosed in ()
next to the endpoint:
query ReturnCustomers {# Access the Customers endpoint# Return five Customers named "John", ordered by their surname (ascending), and not including the first resultcustomers(where: "firstName=\"John\"", sort: "lastName asc", limit: 5, offset: 1) {}}
query ReturnASingleCustomer {# Access the Customer endpoint# Return a Customer based on their idcustomer(id: "{customerID}") {}}
Choose what to return
When querying an endpoint such as customers
(where all Customers are targeted) you can return the following:
offset
is the same value you selected in the parameters.count
is the number of entities returned based on thelimit
parameter.total
is the total number of entities in your Project.exists
returns a boolean value to indicate whether a queried entity exists. For example, when checking whether an email address has already been registered by a Customer.results
is the object where you include the values (such asid
orversion
) you want to be returned.
When querying an endpoint like customer
(where a single Customer is targeted), you only choose the values of the entity to return.
# Query existing dataquery ReturnCustomers {# Access the Customers endpoint# Return five Customers named "John", ordered by their surname (ascending), and not including the first resultcustomers(where: "firstName=\"John\""sort: "lastName asc"limit: 5offset: 1) {# Display the offset, count, and totaloffsetcounttotal# The values to return: The Customer's ID, version, email, and name are returned.results {idversionfirstNamelastName}}}
query ReturnASingleCustomer {# Access the Customer endpoint# Return a Customer based on their idcustomer(id: "{customerID}") {idversionfirstNamelastName}}
Create and update entities
When creating or updating entities within your Project, use mutation
. A name can be included to describe the call.
# Create a new entitymutation CreateDiscountCode{}
# Update an existing entitymutation DeactivateDiscountCode{}
Add an action
Instead of requiring an endpoint, the mutation
requires an action. The chosen action determines whether you are creating a new entity or updating an existing one.
If you are using the GraphQL Explorer, use autocomplete to view a full list of actions.
When creating a new entity
Like with the HTTP API, you must post a draft to create a new entity.
You must also include the values you want GraphQL to return once the entity has been created.
# Create a new entitymutation CreateDiscountCode {# The action for creating a Discount CodecreateDiscountCode(# The DiscountCodeDraft and its required fieldsdraft: {code: "SAVE25"isActive: truecartDiscounts: { typeId: "cart-discount", id: "{cartDiscountID}" }}) {# The values to returncodeisActive}}
When updating an existing entity
Like with the HTTP API, you must post an array of update actions to modify the data of existing entities.
You must also include the values you want GraphQL to return once the entity has been updated.
# Update an existing entitymutation DeactivateDiscountCode {# The action to update an existing entityupdateDiscountCode(version: 1id: "{discountCodeID}"## Include update actions and their required parametersactions: [{ changeIsActive: { isActive: false } }]) {# The values to returncodeisActive}}
Delete entities
When deleting entities within your Project, use mutation
. You can include a name to describe the call.
# Delete an existing entitymutation DeleteDiscountCode {# The action to delete an existing entitydeleteDiscountCode(version: 1, id: "{discountCodeID}") {# The values to returnidcode}}
Try our example calls
The following GraphQL calls demonstrate how to perform the same example calls as in the Manage Customers and Manage Products pages as well as how to use Product Projection Search.
Manage Customers
Create a Customer
mutation CreateCustomer {customerSignUp(# Creating a Customer requires a CustomerDraft which has two required fields: email and password.draft: { email: "graphql@example.com", password: "examplePassword" }) {customer {# Return the new Customer's ID, version, and email address.idversion}}}
{"data": {"customerSignUp": {"customer": {"id": "{customerID}","version": 1,"email": "graphql@example.com"}}}}
Query a Customer
query GetCustomerById {# Access the Customer's endpoint based on their ID.customer(id: "{customerID}") {# Return the Customer's ID, version, email, and name.idversion}}
{"data": {"customer": {"id": "{customerID}","version": 1,"email": "graphql@example.com"}}}
Add a Customer name
mutation AddCustomerName {# The update actionupdateCustomer(# The current version of the Customer. This is 1 for new Customers.version: 1# The ID of the Customer to update.id: "{customerID}"# An array of update actions.actions: [{# The action to change the first name.setFirstName: { firstName: "John" }}{# The action to change the last name.setLastName: { lastName: "Smith" }}]) {# Return the ID, version, email address, and name of the Customer.idversionfirstNamelastName}}
{"data": {"updateCustomer": {"id": "{customerID}","version": 3,"email": "graphql@example.com","firstName": "John","lastName": "Smith"}}}
Find a Customer by their email address
query GetCustomerByEmail {# Access the Customers endpoint, filtering results by the "where" query parameter.customers(where: "email=\"graphql@example.com\"") {results {# Return the Customer's ID, version, email, and name.idversionfirstNamelastName}}}
{"data": {"customers": {"results": [{"id": "{customerID}","version": 3,"email": "graphql@example.com","firstName": "John","lastName": "Smith"}]}}}
Manage Products
Create a ProductType
mutation CreateProductType {createProductType(# Creating a Product Type requires a ProductTypeDraft which has two required fields: name and description.draft: {name: "A new Product Type"description: "Description of the new Product Type"}) {# Return the new Product Type's ID, version, name, and description.idversionnamedescription}}
{"data": {"createProductType": {"id": "{productTypeID}","version": 1,"name": "A new Product Type","description": "Description of the new Product Type"}}}
Create a Product
mutation CreateProduct {createProduct(draft: {# Creating a Product requires a ProductDraft which has three required fields: name, productType, and slug.name: { locale: "en", value: "English Product Name" }productType: { typeId: "product-type", id: "{productTypeID}" }slug: { locale: "en", value: "english-product-name" }}) {# Return the new Product's id, Product Type, version, and published ("current") name.idproductType {id}versionmasterData {current {nameAllLocales {value}}}}}
{"data": {"createProduct": {"id": "{productID}","productType": {"id": "{productTypeID}"},"version": 1,"masterData": {"current": {"nameAllLocales": [{"value": "English Product Name"}]}}}}}
Query your Product
query QueryProduct {# Access the Product endpoint based on its ID.product(id: "{productID}") {# Return the Product's ID, version, and published ("current") name.idversionmasterData {current {nameAllLocales {value}}}}}
{"data": {"product": {"id": "{productID}","version": 1,"masterData": {"current": {"nameAllLocales": [{"value": "{productName}"}]}}}}}
Create a ProductVariant
mutation AddProductVariant {# The update actionupdateProduct(# The current version of the Product. This is 1 for new Products.version: 1# The ID of the Product to add the Variant to.id: "{productID}"# An array of update actionsactions: [{# The action to add a VariantaddVariant: {sku: "myProductVariantSKU"key: "my-product-variant-key"# This field is optional. If false it makes the Variant published ("current").staged: false}}]) {# Return the ID, version, and key and SKU of all the published ("current") Product VariantsidversionmasterData {current {allVariants {keysku}}}}}
{"data": {"updateProduct": {"id": "{productID}","version": 3,"masterData": {"current": {"allVariants": [{"key": "my-product-variant-key","sku": "myProductVariantSKU"}]}}}}}
Retrieve values of enum Attributes in a ProductType
{productType(key: "product-type-key") {attributeDefinitions {results {nametype {name__typename...enumValues...localizedEnumValues}}}}}fragment enumValues on EnumAttributeDefinitionType {values {results {keylabel}}}fragment localizedEnumValues on LocalizableEnumAttributeDefinitionType {values {results {keylabelAllLocales {localevalue}}}}
{"data": {"productType": {"attributeDefinitions": {"results": [{"name": "creationDate","type": {"name": "datetime","__typename": "DateTimeAttributeDefinitionType"}},{"name": "articleNumberManufacturer","type": {"name": "text","__typename": "TextAttributeDefinitionType"}},{"name": "madeInItaly","type": {"name": "enum","__typename": "EnumAttributeDefinitionType","values": {"results": [{"key": "yes","label": "yes"},{"key": "no","label": "no"}]}}},{"name": "color","type": {"name": "lenum","__typename": "LocalizableEnumAttributeDefinitionType","values": {"results": [{"key": "black","labelAllLocales": [{"locale": "en","value": "black"},{"locale": "de","value": "schwarz"}]},{"key": "white","labelAllLocales": [{"locale": "de","value": "weiss"},{"locale": "en","value": "white"}]}]}}}]}}}}
Use Product Projection Search
To be able to use the Product Projection Search endpoint, your product catalog must be indexed first. If indexing is deactivated for your Project, a SearchDeactivated error is returned.
To activate the indexing for your Project, please choose one of the following options:
- via API using the Change Product Search Indexing Enabled update action on the Project endpoint.
- via the Merchant Center by navigating to Settings > Projects Settings > Storefront search.
- via contacting the Composable Commerce support team and provide your region, Project key, and use case.
Search based on text and locale
query {productProjectionSearch(staged: true, locale: "en-US", text: "bed") {total# Uncomment to return the ID and English name of each result.# results{# id# name(locale:"en-US")# }}}
{"data": {"productProjectionSearch": {"total": 17}}}
Search based on text, locale, and filtering
query {productProjectionSearch(queryFilters: [{ string: "published:true" }]staged: truelocale: "en-US"text: "bed") {# Return the total number of results.total# Uncomment to return the ID and English name of each result.# results{# id# name(locale:"en-US")# }}}
{"data": {"productProjectionSearch": {"total": 17}}}
Search using filters
query {productProjectionSearch(staged: truefilters: [{model: {value: { path: "variants.price.centAmount", values: ["1599"] }}}]) {totalresults {idversion}}}
{"data": {"productProjectionSearch": {"total": 3,"results": [{"id": "394f20b4-0b21-45f7-81cc-43a4e45ba775","version": 1},{"id": "ecc60e5f-ddd7-4137-8b84-fcaa17426549","version": 3},{"id": "df65a374-e281-41a1-a370-c4d2591cae39","version": 1}]}}}
Retrieve facet calculation
query {productProjectionSearch(facets: [{model: {range: {path: "variants.price.centAmount"ranges: [{ from: "1000", to: "3000" }]countProducts: false}}}]) {facets {facetvalue {type... on RangeFacetResult {dataTyperanges {type... on RangeCountDouble {fromfromStrtotoStrcountproductCounttotalCounttotalminmaxmean}}}}}}}
{"data": {"productProjectionSearch": {"facets": [{"facet": "variants.price.centAmount","value": {"type": "range","dataType": "number","ranges": [{"type": "double","from": 1000,"fromStr": "1000.0","to": 3000,"toStr": "3000.0","count": 35,"productCount": null,"totalCount": 35,"total": 62065,"min": 1099,"max": 2999,"mean": 1773.2857142857142}]}}]}}}
Differentiate between highPrecision and centPrecision money
{productProjectionSearch(staged: false, locale: "en", text: "blue") {countresults {idmasterVariant {skuprices {...productPrice}}}}}fragment productPrice on ProductPriceSearch {value {...money__typename}discounted {value {...money__typename}__typename}}fragment money on BaseMoney {typecurrencyCodecentAmountfractionDigits... on HighPrecisionMoney {preciseAmount}}
{"data": {"productProjectionSearch": {"results": [{"id": "500797c7-e719-4d72-8c69-92fdee39d451","masterVariant": {"sku": "M0E20000000E582","prices": [{"value": {"type": "highPrecision","currencyCode": "USD","centAmount": 24875,"fractionDigits": 11,"preciseAmount": 24875123456789,"__typename": "HighPrecisionMoney"},"discounted": null},{"value": {"type": "centPrecision","currencyCode": "EUR","centAmount": 16311,"fractionDigits": 2,"__typename": "Money"},"discounted": null}]}}]}}}