Tutorial 8 - Building a Liquid API GET Endpoint Page powered by GraphQL queries
This article shows a different use-case for the skills you've already learned- using a GET request to run a query.
So far, we've written GraphQL queries which run on Page Load. This is powerful, but wouldn't it be even more useful if you could fetch data after Page load when a User interacts with a Site- e.g. changing page on a list without refreshing the Page? Using XHR (sometimes called Ajax) requests, you can run GraphQL at any time.
This approach can take a little bit of time to set up, but can allow you to create much faster interactive experiences for your Users and opens up a huge range of possible solutions you can build. We cannot document every way in which you can build this kind of Page, but we will show you the basics and let your imagination do the rest! If you need additional support on this topic beyond the scope of what is documented here, we recommend you speak to one of our Experts or browse the resources we link to at the end of the Article.
- An API - (Application Program Interface) is a form of communication between two services on the internet. Communication takes place between 2 or more endpoints.
- An endpoint in its simplest form is a URL which allows an API access to a server or application. On Siteglide, we provide you with API endpoints we've built with our public API, but now you've learned GraphQL, you also have the ability to build your own endpoints when you need them.
- A method defines the role of the API + Endpoint e.g. a GET method is for "getting" or "fetching" data.
- JSON (JavaScript Object Notation) is a common file format for exchanging data which is efficient and human-readable. We'll use it in some of our examples. (It's also the default format in which GraphQL results are outputted on the Page.)
The first step is to create a Page on the Siteglide Admin which will become your API endpoint. The slug you choose will be the URL via which you'll eventually access the data. It's worth naming the Page and writing a slug which reflect the fact that this Page is not a public-facing Page and should not be editable by Clients. e.g. /api/webapp_1
In this step, we'll be changing the settings of the Page in CLI, as there are available settings here that are not yet editable from Admin. You can learn more about pages in platformOS here: https://documentation.platformos.com/developer-guide/pages/pages#content and more about the Siteglide-CLI here. Using the Siteglide-CLI, pull down your Site's files to your machine and open them up in a Code Editor of your choice. Set up Siteglide-CLI sync so that changes you make will be pushed to the Site.
Open up the Page you've created in a Code Editor of your choice. We'll be editing the yaml configuration at the top of the page. In my example, you can see the yaml settings between the triple dashes --- It's important when configuring yaml to use exactly 2 spaces instead of tabs for indenting. Your siteglide-cli sync command will alert you to any validation errors.
So far we've only learned to write GraphQL queries, so your endpoint will be handling GET requests. Set the method property of your page to get: method: get
Optionally, you can choose to change the format of your Page. If you like, instead of HTML, you can make your Page a different format, like JSON. format: json
Note that if you set your Page to a different format now, you'll need to append the URL with the extension later. e.g. a Page with the slug my-slug and format JSON can be accessed at the URL /my-slug.json.
As your endpoint Page will not be accessed by either humans or search-engine bots, it's much better to remove the Page Template, allowing you to only return the data you need.
layout: ""
Unless you're using the HTML format from 2) b), you will need to remove any tags automatically added to the Page.
Unlike the other steps, this is not a yaml property on the Page. However, it's included here as a quick sensible step you can take. You may wish to specify in your robots.txt file that pages with this URL should be ignored by search engines.
My example looks like this:
Add a query of your choice using the Liquid graphql tag from tutorial 5 and variables from tutorial 6.
In this example, I'll use the following query to fetch data from webapp_1 and change page with the page variable:
I'll use the following Liquid to run this query when the endpoint Page is accessed: {%- graphql fetch_webapp_1_by_page = "fetch_webapp_1_by_page"-%} Note- I'll be using - before and after my closing Liquid tags to remove unnecessary whitespace from the results- this is optional.
In the example, we'll pass inputs into the endpoint Page using query parameters on the end of the URL, for example, I already have the URL for accessing the endpoint Page: /api/webapp-1.json
Remember
The ".json" extension should be replaced with the "format" you chose in step 2.
I'll be storing the page I want to request from the endpoint in query parameters like so: /api/webapp-1.json?page=2&per_page=1 You can now use context.params`to read the URL on the endpoint Page and dynamically access each query parameter. I'll store each in a variable before I feed these into the query, in case there is any type coercion to carry out first.
Accessing these values via the above method tends to set them as String values in the variable. For this example we'll need to change the type to integer- as that's what the query expects. You can refresh your knowledge on changing the type of variable in Liquid in tutorial 6.
We can then add them to the query.
If the query expects variables to be Strings you can actually add them straight to the query without assigning as variables first:
Results are accessible via the variable name you defined in the graphql tag, but at this point we can decide on the format in which we'll display them.
If you decided in step 2 that you didn't want to change the Page format, you should now build the required HTML structure you'd like to send back (this would probably be inserted as it is into a Page via JavaScript).
If you decided in step 2 to change the format of the Page, you'll need to use Liquid to output the content in this format. As GraphQL already outputs in JSON format, this is easy:
For something like CSV, you'll need to use logic to output the data in the correct format -this is just an example and you may need to alter it for your use-case. We use {% rather than {%- in this example, because we want to preserve new lines to make sure each row of the CSV displays correctly.
In your browser, visit the endpoint Page URL and see if the data displays as expected. Test changing the query parameters to see it change the returned data.
A successful JSON endpoint will return valid JSON in the body, as in the example here (other formats should also be checked for valid formats).
Changing the URL parameters should allow you to return different responses:
Common issues:
- Your URL should include the relevant file extension e.g. .json for json format, .csv for CSV format. If you are using HTML format, no extension is needed. Below is an example of a 404 response from using the incorrect extension:
- Your URL should contain any query parameters you need for your query. E.g. in my example, page and per_page are mandatory. Below is an invalid response body resulting from missing URL parameters:
Congratulations! You've built a working GET endpoint using GraphQL and Liquid! The last two optional steps will expand upon your options for securing the Endpoint and using the data available.
Is your data sensitive and you want only logged in Users to access it? Is your data public and it doesn't need an additional authorisation step? This step shows you some different ways to make sure your data is secure, but you can skip it if your data is not sensitive or private.
Adding a Secure Zone to your endpoint Page is a simple way to protect it from Users and bots who should not be accessing it. A failed access will still generate a successful 2xx response code, because it will succeed in returning HTML body (the 404 message that displays to Users). This is only a problem if you're not using HTML format for your endpoint as it will cause any JavaScript which relies on parsing JSON to fail like so:
In step 9, you'll need to find a way to adapt your JavaScript logic to handle this kind of error which does not rely on the response code, but instead checks the response for the HTML tag <h1>401 - Unauthorised</h1>. See step 9) a) i) and 9) a) ii) for examples of this logic.
You can use Siteglide-CLI and platformOS to build an authorization policy that checks the request either comes from a trusted Site or from a trusted User. The benefit of this is that it allows you to return HTTP response codes. As this is custom platformOS code, it won't be covered by our support. Learn more about authorization policies on the platformOS docs: https://documentation.platformos.com/developer-guide/authorization-policy/authorization-policy
These tips are intended as inspiration and do not constitute complete examples. They do not require sending a query parameter over in your URL, making them easier to keep secure.
- If the User has been logged in (to any Secure Zone), you can check this on the Endpoint Page Authorization policy.
- To check that the request comes from an authorized Page/ Site, you can check this with context:
On any of your other Pages, you can now send requests to your new endpoint and fetch data. For this you could use JavaScript.
The JavaScript examples provided here are intended for inspiration only. Unfortunately, we cannot advise you on how to adapt these to suit individual projects. See the links at the bottom of this Article for more resources you can use to help plan and develop projects of this kind.
This basic example will request data from the example earlier and console log the response.
The if statement logic checks if a 2xx response code is received (meaning any authorization policies have passed) and that there is no HTML tag containing a 401 code from a Secure Zone check failure. See Step 8) for more details.
In this expanded example, we'll fetch the data and then append it to the HTML DOM.
Add HTML and JavaScript
- An event listener targets the Form and watches for a click event
- When the Form is submitted, the event triggers the function "getWebappOne".
- The if statement logic checks if a 2xx response code is received (meaning any authorization policies have passed) and that there is no HTML tag containing a 401 code from a Secure Zone check failure. See Step 8) for more details.
- The function requests the data from our new endpoint.
- It then loops over the Items and appends each WebApp Name to the HTML DOM.
In the previous two examples, we've used an endpoint with a JSON format endpoint. You may find it easier to build HTML on the endpoint and when it arrives in the destination Page, output it as it is. Build HTML on the Endpoint Page
Fetch HTML on the Front End Page
Your Liquid endpoint Page will be acting as an extra Layer between your request and platformOS' own GraphQL endpoint. This extra layer is important because it allows you to run your own logic and security checks, before pOS deliver the data.
- SiteGurus have created the Live Updates API as part of the SiteBuilder module- designed as an incredibly flexible API endpoint for refreshing almost any Siteglide Layout with different filters- this may save you time implementing your own API endpoint: https://www.sitegurus.io/documentation/sitebuilder/live_updates/introduction
- The Siteglide Support Policy explains how you can get support with planning projects and writing custom code.
- MDN have comprehensive documentation on the XML HTTP Request and how to use it in your Front End JavaScript Code: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest You can also use the modern https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API as an alternative.
- Those developers who prefer to use jQuery when writing JavaScript can read more about Ajax Requests here: https://api.jquery.com/jquery.ajax/
- platformOS's documentation on Pages includes lots of information about setting up Pages using the yaml configuration: https://documentation.platformos.com/developer-guide/pages/pages