Skip to main content

About GraphQL

Delivery Gateway uses GraphQL for building its API. This guide walks you through the basics of GraphQL.

About GraphQL

GraphQL is a query language and runtime system. Clients send requests to GraphQL services by using the GraphQL query language, and the service returns the data in a response.

A GraphQL API has a single endpoint for all data. The GraphQL type system describes the data that can be requested from the API. The collection of those data descriptions is called the GraphQL service's schema.

To read or write data, the client must form GraphQL requests using the types defined in the service's schema:

  • Queries: Requests to retrieve data. Essentially, the client is asking for specific fields on pre-defined objects. They're similar to a GET request in a REST API.
  • Mutations: Requests to create and update data. They're similar to a POST or PATCH method in a REST API.

Queries

A GraphQL query requests data from specific fields of one or more objects defined in the schema of the GraphQL service.

The GraphQL request format is similar to JSON but it doesn't use quotation marks for field names. GraphQL services return responses in JSON format. A simple query and response could look something like this:

GraphQL query
query {
providers {
id
name
}
}
JSON response
{
"data": {
"providers": {
"id": "RIV",
"name": "Red Ivorp"
}
}
}

All GraphQL operations start with a root operation type: in this case, it's query. From there you specify the selection set of fields you're interested in: in the example, we're requesting the data from the sender_name field of the merchant object.

The request's result will be returned in a top-level data key. If the request raised errors, the relevant information will be included in a top-level errors key.

Mutations

In a REST API, you send a POST request to a specific endpoint to create or update data. In GraphQL, you use mutations. Mutations are sent to a single endpoint and use the POST HTTP method.

A GraphQL mutation requires:

  • A mutation field name: for example, updateMerchantConfiguration. They are defined in the GraphQL schema.
  • Input data passed as an argument to the mutation field. This is the data that you create or modify.
  • A list of fields that should be included in the JSON response. GraphQL nly returns the data you specifically ask for.

In the example, we create a new delivery zone for a merchant with the createZone mutation and request that the GraphQL API returns the new id, name, and country fields.

GraphQL mutation
mutation {
createZone(
input: {
name: "Hungary",
countries: HU
}
)
{
id
name
countries
}
}
JSON response
{
"data": {
"createZone": {
"id": "45678",
"name": "Hungary",
"countries": [
"HU"
]
}
}
}

Arguments

A GraphQL service can pass arguments to fields: this means that the client must provide a value for the required argument when sending a query or a mutation. For example, you can specify the ID of a provider to query pickup point availability:

GraphQL query
query {
shipment(id: 215099) {
provider
mode
}
}
JSON response
{
"data": {
"shipment": {
"provider": "Red Ivorp",
"mode": "SENDER_TO_RECIPIENT"
}
}
}

Variables

Variables allow you to reuse the same GraphQL requests with dynamic values. Variables are declared after the query or mutation keyword, like passing an argument to a function. They always begin with the $ symbol.

A variable declaration works this way:

  • Declare a $variableName.
  • Specify the type of the variable, for example, createShipmentInput!.
  • Replace the static value in the query or mutation with $variableName.
mutation($input: createShipmentInput!) {
createShipment(input: $input) {...}
}

Define the actual values for the variable in a separate variables dictionary that's usually in a JSON format.

{
"input": {
"provider":"Pro Vider",
"referenceId":"12345",
"recipient":{
"firstName":"Fictitious",
"lastName":"Customer",
"language":"EN"
},
"destination":{
"pickupPointId":"12345"
}
}
}

Nested objects

In both queries and mutations, you will often need to use nested objects. In GraphQL, nested objects let you query multiple related data points in a single request, instead of using multiple endpoints like in a REST API.

For example, you can query the ID and name of all providers in a single request by using nesting:

GraphQL query
query {
providers {
id
name
}
}

Nesting applies to both responses and inputs. Many mutations have nested inputs. For example, the OrderBillingInput type requires multiple fields, including name, email, and phone number:

GraphQL mutation
mutation {
upsertOrder(
input: {
billing: {
name: "Most Excellent Customer",
email: "examplemail@example.org",
phone: "00 01 123 4567",
vatNumber: "8337961152"
isCompany: true
}
}
)
}

You can nest within nested objects, too:

GraphQL mutation
mutation {
upsertOrder(
input: {
billing: {
name: "Most Excellent Customer",
email: "examplemail@example.org",
phone: "00 01 123 4567",
vatNumber: "8337961152"
isCompany: true,
address: {
country: CA,
state: "Ontario"
city: "Ottawa",
postalCode: "K2C 0A6",
addressLine1: "1026 Baseline Rd",
addressLine2: "Building B, 4th floor"
note: "The receptionist is grumpy"
}
}
}
)
}

In this example, we added an address field that requires the AddressInput type. For a valid mutation containing the address field, you need to specify multiple fields in a nested object, including country, state, and city.

Multiple queries in the same request

You can submit multiple queries or mutations in a single GraphQL request. These operations can be different or you can also query the field or run the same mutation multiple times with different arguments.

To submit multiple queries or mutations:

  • Declare whether the operation is a query or a mutation.
  • Give each operation a custom alias and place it before the name of the query or mutation: custom-alias: updateMerchantConfiguration.

In this example, we create three different pricing rules:

GraphQL mutation
mutation {
BasicPricing: createPricing(
input: {
name: "Basic rule"
price: {
amount: 5,
currency: EUR
}
}
){
name
}
HomeDeliveryPricing: createPricing(
input: {
name: "Home Delivery Pricing"
price: {
amount: 5,
currency: EUR,
condition: {
isHomeDelivery: true,
}
}
}
){
name
}
PickupPricing: createPricing(
input: {
name: "Home Delivery Pricing"
price: {
amount: 5,
currency: EUR,
condition: {
isPickupPoint: true,
}
}
}
){
name
}
}