Feeding Data into AMP Pages with GraphQL
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.
- Developer Guide: Pages
- Developer Guide: Using a Static AMP Template
- Developer Guide: Converting AMP HTML Pages to Layouts and Pages
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
app/views/pages/product-list.liquid
---
layout: 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 app/views/layouts/application.liquid
:
{% yield 'amp-dependencies' %}
Notes
- The data source for
<amp-list>
isproducts.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.
app/views/pages/api/products.json.liquid
{% liquid
graphql g = 'get_products'
assign results = g.products.results
%}
{
"items": [
{% for product in results %}
{
"name": {{ product.name }},
"slug": {{ product.slug }},
"description": {{ product.description }},
"image": {{ product.photo.url }},
"price": {{ product.price }}
}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
}
Notes
- The GraphQL query is not given any argument, thus it retrieves all the 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 product data
Create the GraphQL query that fetches product data.
app/graphql/get_products.graphql
query get_products($slug: String) {
products: records(
filter: {
table: { value: "product" }
properties: [
{ name: "slug", value: $slug }
]
}
per_page: 100
) {
total_entries
results {
name: property(name: "name")
slug: property(name: "slug")
description: property(name: "description")
photo: property_upload(name: "photo") { url }
price: property(name: "price")
}
}
}
Notes
- If the optional slug argument is omitted, then it returns all products.
price
is a property defined in the product Table's .yml file, which is found in theschema
directory.
app/schema/product.yml
name: product
properties:
- name: name
type: string
- name: slug
type: string
- name: description
type: string
- name: price
type: float
- name: photo
type: upload
Step 4: Display product details
Create the /product-details
page that loads when visitors click on a product from /product-list
above.
app/views/pages/product-details.liquid
---
layout: application
---
{% liquid
graphql g = 'get_products', slug: params.slug2
assign product = g.products.results.first
%}
<h1>{{ product.name }}</h1>
<amp-img src="{{ product.photo.url }}" layout="responsive"></amp-img>
<p>${{ product.price }}</p>
<p>{{ product.description }}</p>
Notes
- The page at
/product-list
passes the product slug to this page through the URL, which is formed as/product-details/<listing_slug>
- Then you pass on the product's slug to the GraphQL query (
slug: params.slug2
), to find the product details. - This is the same GraphQL query that you used on the other page to retrieve all products, but this time you call it with the product slug to find just one product.