Next.js + GraphQL + Saleor

  • user
    Martin, RvT
  • date
    February 09, 2023
Next.js + GraphQL + Saleor

San prides itself on delivering quality solutions in a timely fashion, and so building a fully functioning e-commerce store from scratch in just weeks was right-up our street. Plus, like all interesting projects, it generated some fascinating new skills.

Technology Platforms

The client, a leading energy technology company, needed a store to sell their services and products with a lot of customer choice. They could select different product variants and several payment options, and could come directly or via third-party partners. That made tool selection critical.

The React framework Next.js came top of the list for building the core application. Its many benefits included:

  • server-side rendering
  • search engine optimisation
  • automatic route creation

Route creation was particularly helpful - simply drop your component in /pages and you have a functional URL path with no other manual router configuration required. This neatly lends itself to e-commerce applications where lots of page redirection can be required as the user navigates the shop/basket/checkout/payment and potentially ‘next steps’ journey.

Saleor - an open-source e-commerce platform, was selected to handle products and orders. It promised ultra-fast, dynamic and personalised shopping experiences that fitted our client’s requirements.

Stripe was used for payment integration, while Contentful was used for content management. Additionally a number of bespoke AWS lambda functions were created to facilitate and automate our client’s back-end post-order processes.

Using these tools built on serverless framework further reduced cost and improved ease of scalability. While our familiarity with most of these tools made life easier and sped-up development.

Data Interaction via GraphQL

Starting with building the core framework of the UI, we needed next to communicate with the e-commerce platform in order to retrieve product information and place orders.

Interaction with Saleor is built entirely around GraphQL:

  • Want to get a list of your categories or products? Use a GraphQL query.
  • Want to create a checkout or order? Use a GraphQL mutation.

With coming from a background in REST this was a learning opportunity! Fortunately, the learning curve was not steep, and there are plenty of YouTube videos to help get started. We recommend Web Dev Simplified’s “Learn GraphQL in 40 minutes”.

A major benefit working with GraphQL over REST are instances where you are missing some data from an API response which you want to make use of in the front-end. With GraphQL there is no need to make a new call (and potentially mash up your data client-side with some manual transformation to create the object you really want) as you might do when working with REST APIs.

Instead, simply add the missing field into your query in the existing request. So long as that field is available in the GraphQL schema, this makes fleshing out your front-end data so much simpler.

There were several times when this to lead to cleaner code and significant time savings, compared to previous REST-based applications we have written.

Here’s an example query to list the id, name and description of the first product. Simply include the fields you wish to be returned:

query {
  products(first: 1, channel: "default-channel") {
    edges {
      node {
        id
        name
        description
      }
    }
  }
}

Response (id, name, description):

{
  "data": {
    "products": {
      "edges": [
        {
          "node": {
            "id": "UHJvZHVjdDoxOTY=",
            "name": "1970-1982",
            "description": "{\"time\": 1660756037554, \"blocks\": [{\"id\": \"0\", \"data\": {\"text\": \"\"}, \"type\": \"paragraph\"}], \"version\": \"2.23.1\"}"
          }
        }
      ]
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 2,
      "maximumAvailable": 50000
    }
  }
}

Modifying data (e.g. creating/updating checkout objects and orders) follows a similar pattern. In GraphQL mutations and inputs are used for manipulating data, and here the Saleor API reference documentation comes in very useful.

Example - creating a checkout through adding a product variant. Specify the mutation and your desired return fields:

mutation {
  checkoutCreate(
    input: {
      channel: "uk-channel"
      lines: [{ quantity: 1, variantId: "UHJvZHVjdFZhcmlhbnQ6NDAz" }]
    }
  ) {
    checkout {
      id
      totalPrice {
        gross {
          currency
          amount
        }
      }
    }
  }
}

Saleor also provides a GraphQL playground connected to a test site populated with sample data, and we made frequent use of this for safely building and testing potential queries in an open sandbox environment.

Post-Order Processing

For facilitating bespoke processes, Saleor allows custom metadata to be added to any object. Again, GraphQL queries and mutations are available to get and set this data. We used this to track the customer’s web entry route into the store – which our client needed - and this metadata is easily accessible on the Saleor dashboard, which is a delivered UI front-end onto the API.

A number of built-in webhook events are available which your application can subscribe to. Here we made use ORDER_CREATED via a custom lambda function to trigger our post-order workflow (email order confirmation etc.).

Shopping Basket

With a Stripe integration included to process payments our solution was complete, and we were able to move the application from requirements stage to production-ready in around the same time it took to complete the World Cup group phase! Not that that was distracting at the time.

Tags:
Get in touch

Let’s do something great