Getting Started with the Operator API

Here we will get started on how to use the Operator API

The Marketplacer GraphQL API allows developers to connect to a Marketplacer site to retrieve and modify data. Using this API it is possible to build a custom front-end to Marketplacer, to connect to a different eCommerce system, syndicate products, power a native mobile app and more.

This tutorial will cover the steps required to start querying data using the Marketplacer GraphQL API.

The first thing that is required to connect to the API is an API key.



If you prefer video to the written word, then the following video takes you through setting up the Marketplacer Operator API.




Getting your API key

Your site has API keys that are accessible under the Configuration menu in the administration portal.

API link


In order to generate a key you’ll need to:

  • Provide a description for the key - this helps when you have multiple keys used for different purposes
  • Provide the name of the organization agreeing to the API License
  • Accept that you have read the API License agreement

Before we make our first API call, be sure to take note of the API endpoint URL for your Marketplacer instance as identified on the New API Key page.

Testing our API key

We can test that our API key works by performing a search for products (aka “adverts”) on your Marketplacer instance. We can can use any number of tools to execute our query, including but not limited to:

  • Postman
  • Insomnia
  • cUrl

In our walk-through we’re going to use Insomnia.

Step 1 - Set Up Insomnia

Having downloaded Insomnia, start the app and create a new Request Collection:

New Request Collection


Name your collection, then create a new GraphQL request:

New GraphQL Request


Supply your GraphQL API endpoint in the URL box, (you are provided this endpoint when you generate your API Key), an example endpoint is used below:


API Endpoint


Note: All GraphQL API requests go to the same /graphql endpoint, so ensure this is in the supplied URL.

Step 2 - Pass the API Key

Ultimately the API Keys gets passed as a request header, but there are 2 variations on this:

  1. Pass the key an authorization header using the bearer scheme
  2. Configure a marketplacer-api-key header directly with the API key passed as the value

You can use either method, (not both!), however if your Marketplacer instance is further protected by Basic Authentication (as well as an API key - which is always the case) you should use the 2nd method: passing the API Key as a direct marketplacer-api-key header.

2a Passing as a Bearer Token

To pass the key as an authorization header using Insomnia, select the Auth tab, then select Bearer Token:

Configure Bearer Token


Then supply your API key as the token value:

Bearer Token

2b Passing as a marketplacer-api-key

As mentioned above you can pass your API key directly as a header, to do so select the headers tab and click Add, then enter the following:

  • Header: marketplacer-api-key
  • Value: Your API key

This is show below:

Marketplacer Header


This is all you need to do if your Marketplacer instance is only protected by an API Key, optionally if Basic Authentication enabled you will need to supply those credentials by configuring Basic Authentication:

Configure Basic Authentication


Then supply your Basic Authentication Username and password - these can be provided to you by your Marketplacer representative.

Step 3 Execute a query

Enter the following GraphQL query into the GraphQL section of Insomnia:

query SearchForProducts
{
  advertSearch
  {
    adverts{
      nodes{
        id
        title
      }
    }
  }
}

Clicking Send, you should get a successful response, along with a JSON payload of any returned products.

Advert Search Response


While this Getting Started Guide is not a full introduction to GraphQL, it’s worth identifying some key concepts with the query in its current form.

query SearchForProducts # Operation Name - defined by the developer
{
  advertSearch # Query Name - defined by the Marketplacer API schema
  {
    adverts{ # Object types returned
      nodes{ # Nodes collection
        id   # ID field of the Advert
        title # Title field
      }
    }
  }
}

These concepts are explained further below:

  • Operation Name: You should always “name” your GraphQL queries and mutations, otherwise they will be considered anonymous. Indeed many API clients (Insomnia included) may have an issue executing your query if you don’t include an Operation Name. For more insight into this refer to our Best Practices Guide. You can name operations as you like, but they should attempt to briefly describe what the operation is doing.
  • Query Name: This is the name of the query as defined by the Marketplacer API
  • Object Types: In the case of this particular query (advertSearch) the objects that are returned are a collection of Adverts (aka Products).
  • Nodes: Irrespective of the concrete object type (Advert), we use the generic nodes collection to return our Adverts (Advert like most of the objects in the Marketplacer API implement the generic node object). You’ll see the use of nodes in all of our query examples - more on Edges and Nodes below.
  • Field Selection: In this example we are only selecting 2 fields available on the Advert object:
    • id: The Marketplacer identifier for the Advert
    • title: The Advert title

Note: You can add many more fields to the query as required - but only add additional fields if they are required to service your business use-case.

Requesting every available field for a given object is rarely required and would make your integration unnecessarily inefficient.

Improving our query

The example query is very simple, but even so, it does not adhere to our best practices for writing GraphQL queries. Let’s fix that!

Improvement #1 - Paginate your data

In any scenario where you can expect more than 1 result, you are required to paginate your data - meaning that you specify a maximum number of results (up to 500 in the case of the Marketplacer API) that you want per request - this is otherwise referred to as the Page Size.

Pagination with our GraphQL API is discussed in full here so we won’t repeat that content, instead we’ll just update our query to use pagination:

query SearchForProducts {
  advertSearch {
    adverts (first: 10, after: null) {
      totalCount
      pageInfo{
        hasNextPage
        endCursor
      }
      nodes {
        id
        title
      }
    }
  }
}

Here you can see that:

  • We are specifying the first 10 results (this is the page size)
  • We are not specifying (yet) a cursor via the after attribute to bring back the next page of results.
  • We have added totalCount count to give us the total number of Adverts matching this query
  • We have added the pageInfo object, containing:
    • hasNextPage: this is a true or false value telling us whether there is more data to retrieve.
    • endCursor: If we have another page of data to retrieve, (hasNextPage = true) then this value can be supplied to our after attribute to give us that data

Looking at the response to this query now (focusing on the pagination elements) we see something like:

{
  "data": {
    "advertSearch": {
      "adverts": {
        "totalCount": 448,
        "pageInfo": {
          "hasNextPage": true,
          "endCursor": "WzAsMTY5NTg5MDE5MywxLjY0MjY0MDYsMTUzOV0"
        },
        "nodes": [
          {
            "id": "QWR2ZXJ0LTEwMDA5MzA0Ng==",
            "title": "Clutch Bag"
          }
          .
          .
          . 👈 A further 9 products here (not shown) 
        ]
      }
    }
  }
}

Improvement #2 - Use variables

This improvement flows on nicely from our last one (pagination) in the respect that we hard-coded values in that query, specifically:

  • first (hard-coded value of 10)
  • after (hard-coded value of null)

If we wanted to page through the full result set (all 448 products in this example), using the hard-coded approach above we’d need to actually update the GraphQL query code every time - this is not good practice. Instead GraphQL allows us to pass these values as variables, allowing us to leave our code untouched. An updated example using variables for our pagination values is shown below:

Query (GraphQL)

query SearchForProducts ($pageSize: Int, $cursor: String){
  advertSearch {
    adverts (first: $pageSize, after: $cursor) {
      totalCount
      pageInfo{
        hasNextPage
        endCursor
      }
      nodes {
        id
        title
      }
    } 
   }
}

Variables (JSON)

{
	"pageSize": 15,
	"cursor": "WzAsMTY5Mzc5ODI3NiwxLjY0MjIyNjcsNDQzNF0"
}

The changes we have made are:

  • Constructing a JSON variable payload with 2 attributes:
    • pageSize
    • cursor
  • Defining the variables we want to accept in our query, this is done after the query operation name (SearchForProducts). Noting:
    • We give the variables the same names as in our JSON payload except we prefix a $
    • We have to define the correct data type for each
  • We update the hard-coded values in our query and replace them with the GraphQL variable names

API clients like Postman and Insomnia allow you to construct your queries in this way and pass variables. An example of how this looks is Insomnia is shown below:

Insomnia Variables

Further improvements

We’ll leave our simple query there for now, but for more tips on writing well-formed GraphQL queries and mutations, please refer to our Best Practices Guide.

Understanding Edges and Nodes

The Marketplacer GraphQL API follows the Relay Specification. This defines how data is returned when a one-to-many relationship is involved and is useful for paginating results. In this design, a node has attributes as well as connections to other nodes. A node represents one objects while an edge is the relationship between two nodes.

Edges and Nodes

In the diagram above, Advert, Variant and Image are all nodes and the links between the nodes are all edges. When navigating through the data structure returned by the Marketplacer GraphQL API you will need to use the node and edge concepts to get to the data you’re interested in.

Queries and Mutations

In the previous examples we performed a Query against the GraphQL API. As its name suggests, a Query is a way to retrieve data from the API. Which attributes are returned is determined by the query you perform.

If you wish to update data, you need to use a Mutation instead. An example of a Mutation in the Marketplacer GraphQL API is orderCreate which (no surprises), creates an order for a given Product (we actually pass this mutation variant id as you’ll see in the example below).

IDs

The Node interface defined by Relay gives all objects a globally unique ID that can be used for looking up objects. This ID must be unique across all entities in the API - an advert cannot have the same ID as a Variant or an Order, for example. When given an ID, the API must be able to fetch the right object without knowing the type of object. This means that the IDs used in the GraphQL API are not the same IDs used in the admin & seller portals. In the case of both the Seller and Operator portals, the Ids we present there would be represented by the legacyId field on most GraphQL objects.

For a longer discussion on Marketplacer IDs, please refer to this article.

Example Mutation

In this section we will create a simple order, this will be a two-step process.

  1. First we must find a variant which can pass to orderCreate.
  2. We will then create the order using orderCreate.

Finding a variant

A variant represents a purchasable variation of a product (aka Advert). For example, it may represent the small size of a t-shirt. Even if there are no size variations, an advert will always have a variant which is the item that must be “ordered”.

We can perform a search for adverts and request variants to be returned, we will re-use our previous query but with some additions:

  1. We will pass a keywordQuery attribute to enable us to filter down our result set - this will of course be passed as a variable.
  2. We will expand our GraphQL query (code) to further bring in Variants on the Advert. Note that we should also paginate on our variant result set. With this in mind we have altered the variables that we pass to support this.

Query (GraphQL)

query SearchForProducts(
  $advertPageSize: Int
  $advertCursor: String
  $variantPageSize: Int
  $variantCursor: String
  $attributes: AdvertSearchInput
) {
  advertSearch(attributes: $attributes) {
    adverts(first: $advertPageSize, after: $advertCursor) {
      totalCount
      pageInfo {
        hasNextPage
        endCursor
      }
      nodes {
        id
        title
        variants(first: $variantPageSize, after: $variantCursor) {
          totalCount
          pageInfo {
            hasNextPage
            endCursor
          }
          nodes {
            id
            label
          }
        }
      }
    }
  }
}
    

Variables (JSON)

{
	"advertPageSize": 15,
	"advertCursor": null,
	"variantPageSize": 5,
	"variantCursor": null,
	"attributes": {
		"keywordQuery": "Evening Wear"
	}
}

In this case we get a single result:
{
  "data": {
    "advertSearch": {
      "adverts": {
        "totalCount": 1,
        "pageInfo": {
          "hasNextPage": false,
          "endCursor": "WzAsMTY1NTc3NDI1Myw2Ljk5NDA5LDIwODhd"
        },
        "nodes": [
          {
            "id": "QWR2ZXJ0LTEwMDAxNzY4OQ==",
            "title": "Classic Black Dress",
            "variants": {
              "totalCount": 1,
              "pageInfo": {
                "hasNextPage": false,
                "endCursor": "MQ"
              },
              "nodes": [
                {
                  "id": "VmFyaWFudC0yMTc2OA==", 👈 We want this id
                  "label": "Black / Size 14"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

We now have the ID of a variant that we can use to create an order.

Creating an order with orderCreate

The orderCreate mutation lets us create an order by passing a valid variant id, so to round out our introduction, a simple example is provided below:

For a full discussion on this important mutation, please refer to this article.


Mutation (Graphql)

mutation CreateOrderUS($input: OrderCreateMutationInput!) {
  orderCreate(input: $input) {
    status
    errors {
      field
      messages
    }
    order {
      id
      invoices {
        edges {
          node {
            id
            legacyId
            lineItems {
              id
              quantity
            }
          }
        }
      }
    }
  }
}

Variables (JSON)

{
  "input": {
    "order": {
      "firstName": "Jane",
      "surname": "Doe",
      "phone": "0405123456",
      "billingFirstName": "John",
      "billingSurname": "Doe",
      "emailAddress": "john@email.com",
      "billingEmailAddress": "john@email.com",
      "address": {
        "address": "9001 Belmart Rd",
        "city": "Potomac",
        "country": {
          "code": "US"
        },
        "postcode": "20854",
        "state": {
          "short": "MD"
        }
      },
      "billingAddress": {
        "address": "9001 Belmart Rd",
        "city": "Potomac",
        "country": {
          "code": "US"
        },
        "postcode": "20854",
        "state": {
          "short": "MD"
        }
      }
    },
    "lineItems": [
      {
        "variantId": "VmFyaWFudC0yMTc2OA==", 👈 Variant Id passed as a lineItem
        "quantity": 1,
        "cost": {
          "amount": 9900,
          "tax": 45
        },
        "postage": {
          "amount": 100,
          "tax": 0
        }
      }
    ]
  }
}

Running this mutation will result in the following JSON response, where you can see that we have a successfully created order (ID: T3JkZXItMTMzNzU=):

{
  "data": {
    "orderCreate": {
      "status": 200,
      "errors": null,
      "order": {
        "id": "T3JkZXItMTMzNzU=",
        "invoices": {
          "edges": [
            {
              "node": {
                "id": "SW52b2ljZS0xMzQ3MQ==",
                "legacyId": 13471,
                "lineItems": [
                  {
                    "id": "TGluZUl0ZW0tMzgzNA==",
                    "quantity": 1
                  }
                ]
              }
            }
          ]
        }
      }
    }
  }
}

Further reading

The Marketplacer GraphQL API covers the queries and mutations you need to search, browse and display adverts and sellers as well as creating carts and orders. Read the full documentation to find out more, or interactively explore the schema with GraphQL Voyager.