Feeding Data into AMP Pages with GraphQL

Last edit:  Jan 17, 2019

Contributors:  pavelloz lemingos

This guide will help you feed data into your AMP pages using GraphQL. The guide explains the process through a real-life example of displaying products of an online store.

The guide explains the process through a real-life example of displaying products of an online store.

Requirements

This is an advanced tutorial. To follow it, you should be familiar with basic platformOS concepts, technologies, and the topics in the Get Started section, especially pages. You should also know what AMP pages are and how to create them.

Steps

Feeding data into AMP pages with GraphQL, in this case, displaying products on a page is a four-step process:

Step 1: Display list of products

Create the main page, HTML extended with AMP tags and objects marketplace_builder/views/pages/product-list.liquid:

---
slug: product-list
layout_name: application
---

{% content_for 'amp-dependencies' %}
  <script custom-element="amp-list" src="https://cdn.ampproject.org/v0/amp-list-0.1.js" async></script>
  <script custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js" async></script>
  <script custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.1.js" async></script>
{% endcontent_for %}

[...]
<amp-list src="api/products.json" layout="responsive">
  <template type="amp-mustache">
    <a href="/product-details/{% raw %}{{ slug }}{% endraw %}">
      <div>
        <amp-img src="{% raw %}{{ image }}{% endraw %}" width="300" layout="responsive" noloading></amp-img>
        <h2>{% raw %}{{ name }}{% endraw %}</h2>
        {% raw %}{{ description }}{% endraw %}
      </div>
      <div>${% raw %}{{ price }}{% endraw %}</div>
    </a>
  </template>
</amp-list>

Include the AMP dependencies in the layout file marketplace_builder/views/layouts/application.liquid:


{% yield 'amp-dependencies' %}

Notes

  • The data source for <amp-list> is products.json.
  • amp-mustache enables the 'mustache' (double curly braces) templating syntax.
  • The {% raw %} tag instructs the liquid preprocessor not to interpret the liquid tags, and leaves them to AMP/mustache to process.

Step 2: Create JSON endpoint

Create the JSON endpoint, a dynamically generated JSON document from which AMP fetches the data that it displays marketplace_builder/views/pages/api/products.json.liquid:

---
slug: api/products
format: json
---

{% query_graph 'get_listings', result_name: g %}
{% assign results = g.listings.results %}

{
  "items": [
    {% for listing in results %}
      {
        "name": {{ listing.name | json }},
        "slug": {{ listing.slug | json }},
        "description": {{ listing.description | json }},
        "image": {{ listing.photos[0].url | json }},
        "price": {{ listing.price }}
      }{% unless forloop.last %},{% endunless %}
    {% endfor %}
  ]
}

Notes

  • The GraphQL query is not given any argument, thus it retrieves all the listings (products) which are then sorted by price in ascending order with the sort: liquid filter.
  • Then the for loop populates the "items" list with JSON data that contains the info for each product.
  • The loop puts a comma after each element except for the last in the list.

Step 3: Fetch listing data

Create the GraphQL query that fetches listing data marketplace_builder/graph_queries/get_listings.graphql:

query get_listings($slug: String) {
  listings(
    listing: {
      is_deleted: false
      slug: $slug
    }
  ) {
    total_entries
    results {
      name
      slug
      description
      photos { url }
      price: property(name: "price")
    }
  }
}

Notes

  • If the optional slug argument is omitted, then it returns all listings.
  • price is a property defined in the Transactable Type's .yml file, which is found in the transactable_types directory:
[...]
properties:
- name: price
  type: float

Step 4: Display product details

Create the /product-details page that loads when visitors click on a product from /product-list above views/pages/product-details.liquid:

---
slug: product-details
layout_name: application
---

{% query_graph 'get_listings', result_name: g, slug: params.slug2 %}
{% assign product = g.listings.results.first %}

<h1>{{ product.name }}</h1>
<amp-img src="{{ product.photos[0].url }}" layout="responsive"></amp-img>
<p>${{ product.price }}</p>
<p>{{ product.description }}</p>

Notes

  • The page at /product-list passes the listing (product) slug to this page through the URL, which is formed as /product-details/<listing_slug>
  • Then we pass on the listing's slug to the GraphQL query (slug: params.slug2), to find the product details.
  • This is the same GraphQL query that you used in the other page to retrieve all listings, but this time you call it with the listing slug to find just one listing.

Questions?

We are always happy to help with any questions you may have. Check out our Help page, or contact us.