Getting Started with the Operator API
12 minute read
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.
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
Key Retrieval
Once an API key has been generated, and you browse away from the key generation page, you will not be able to retrieve the key again.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.
API Collections
We have API collections for both Insomnia and Postman that are available here for download, these include a wide range of examples for most use cases that you’re going to encounter. This is the quickest way to get started - we even have a series of videos that take you through how to set up these collections.Step 1 - Set Up Insomnia
Having downloaded Insomnia, start the app and create a new Request Collection:
Name your collection, then create a 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:
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:
- Pass the key an authorization header using the
bearer
scheme - 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
:
Then supply your API key as the token value:
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:
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:
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.
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 ofAdverts
(aka Products). - Nodes: Irrespective of the concrete object type (
Advert
), we use the genericnodes
collection to return our Adverts (Advert
like most of the objects in the Marketplacer API implement the genericnode
object). You’ll see the use ofnodes
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 theAdvert
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 atrue
orfalse
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 ourafter
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 ofnull
)
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 give the variables the same names as in our JSON payload except we prefix a
- We update the hard-coded values in our query and replace them with the GraphQL variable names
GraphQL Vs JSON
GraphQL and JSON are syntactically very similar, but they are different, so it’s easy to confuse the 2 especially when we’re using both - so be careful!
In short:
- GraphQL Queries and Mutations are written in GraphQL (not surprisingly!)
- Variables are passed as JSON
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:
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.
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.
- First we must find a variant which can pass to
orderCreate
. - 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:
- We will pass a
keywordQuery
attribute to enable us to filter down our result set - this will of course be passed as a variable. - 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 orders. Read the full documentation to find out more, or interactively explore the schema with GraphQL Voyager.