Hygraph is a headless content management system (CMS) that promotes composability within a content infrastructure. It offers native GraphQL integration that facilitates efficient data retrieval and enables Content Federation to create unified content experiences.
Svelte is a JavaScript framework known for its distinctive approach to user interface development. Svelte's focus on simplicity, performance, and developer experience has increased its popularity within the web development community.
This article will closely examine federated content management using Hygraph and Svelte. Specifically, we will explore a use case demonstrating content integration from Federate This using GraphQL and discuss the optimal method for establishing a GraphQL connection to Svelte.
#Prerequisites
To comfortably follow along, you’ll need the following:
- Node.js installed
- Basic knowledge of JavaScript and Svelte
- A free-forever Hygraph account
- Basic knowledge of GraphQL
#What is Content Federation?
Content Federation refers to the process of aggregating data and content from multiple sources and presenting it to users through a unified API endpoint as if sourced from a singular origin. This approach allows seamless access to information from various sources, facilitating efficient data management.
Hygraph, a prominent Content Federation player, offers a suite of mock data APIs via Federate This. These APIs used for demo purposes can be added alongside other APIs in a Hygraph project and queried via a single API.
Let’s explore Hygraph’s Content Federation support using the "Products routes" provided on Federate This and create a Hygraph model.
The “Products routes” showcase a list of dummy products. We will add this route as a remote source on Hygraph — but to do that, you’ll need an account with Hygraph. You can get a free-forever developer account if you don't have one.
#Setting up a Hygraph project
After creating an account on Hygraph, you’ll be prompted to go to create a new project.
By clicking “Add project,” we see the view below, where we add our project's name, description, and region.
After filling in the necessary fields, click "Add project" to finalize the process. This action leads us to the project statistics page, providing an overview of the newly created project.
#Adding a remote source
Hygraph facilitates Content Federation through its "remote source" feature. To import data from the "Products routes" into Hygraph, create a remote source within the Hygraph project. To do so, navigate to Schema > Remote Sources and click on the "+Add" button, as illustrated below:
Clicking on the "+Add" button opens a form, where we’ll fill in the following details:
- Display name: Enter "Product Source"
- Type: Select "GraphQL"
- Base URL: Enter the endpoint for our "Product routes"
(https://federatethis.com/api/graphql/products
), which we will use for queries
For a visual guide, please watch the video below:
Once these details are filled in, the view should look like the below:
To make queries or request data from a remote source, we can use different methods such as:
Remote content: This allows us to add data from external systems directly in Hygraph models, and it can be achieved via remote fields and top level remote fields.
Custom types: Uses GraphQL types that work together with Hygraph’s autogenerated types to create a unified schema for the Hygraph content and the remote data.
Custom input type: Defines input parameters using GraphQL types when making queries to a remote source.
Remote fields enable external data retrieval, and in this implementation, we will use the “remote fields” method due to its tight integration with Hygraph models, which will give us more granular control over data fetching. To do this, we will create a model and add the “products” fields as part of its fields.
#Setting up a model
In Hygraph, a model serves as a content blueprint. Within a model, we can define fields that outline the content's schema and illustrate how various content pieces are interconnected.
To create a model, navigate to Schema > Models and click on “+Add” as seen below:
This opens up the modal below, which we fill with the appropriate information. In our case, we want to add a “Store” model.
By selecting "Add Model," we create a Store model. Next, we will define fields for this model. Specifically, we’ll create three fields: "name", "city" and “products” - where “products” will be a remote field from the products “remote source” we added earlier.
To add these fields, navigate to the right sidebar under the "Add Fields" header and choose the appropriate data type for each field.
Both "name" and "city" are string fields for this model. Therefore, we will select "Single line Text" and provide the required information. Repeat this step for the "city" field.
To add the “products” field, select “GraphQL” as the type of field. In the “Remote Source” we can already see the “Product Source” selected, so we will leave it as it is. We will add the display name as “products” and select the query as “Products” query. We will not add any “input argument” as we want to get all the products.
At this point, we should have our view looking like this:
The “Store” model should also look like the below:
#Adding content to the Store model
With the "Store" model created, we will now add content to it. To do this, navigate to Content > Default views, where you’ll find the Store model we created. To add content, click the "+Add entry" button located at the top right corner of the page, as depicted in the image below:
Clicking on the button brings up the view below, where we will input the provided information and save it.
Upon completion, the view should look like the one depicted below:
Now that we have the content set up let’s query this data from the API playground. Copy the query below into the playground.
query MyQuery {stores {cityname}}
Running this query returns the response below:
In the image above, the response displays the content of the fields defined in the "Store" model.
Now, let’s enhance the query by including a request to fetch the "Product routes" we previously imported via a Hygraph remote source. Copy the provided query into the API playground and execute it.
query MyQuery {stores {citynameproducts {idimagenamepricedescription}}}
In the image above, we can view the response tab, which shows data for both the products and the store’s content.
With this configuration in place and the response successfully displayed, let’s explore how we can query and present this data in a Svelte app.
Recommended reading
#Setting up a Svelte app
We‘ll create a new Svelte app using the npm create svelte@latest
command. This will also provide a list of options for selecting the appropriate fit for the project.
Which Svelte app template?Select > Skeleton projectAdd type checking with TypeScript?Select > No //You can select a different option for thisSelect additional options (use arrow keys/space bar)Select > Add ESLint for code linting, Add Prettier for code formatting
Styling a Svelte app with Tailwind CSS The CSS framework we will use in this project is Tailwind CSS, which you’ll need to configure by following the installation steps here.
#Making GraphQL connection with a Svelte application
Connecting a GraphQL endpoint with a Svelte application happens in various ways. One such way is through the use of “graphql-request”.
graphql-request is a lightweight and intuitive API that makes integrating Svelte applications with GraphQL APIs easy without introducing unnecessary complexity. With graphql-request, we can quickly fetch data from GraphQL APIs using asynchronous programming techniques such as async/await, aligning well with Svelte's reactive programming model.
Now, let’s connect our Hygraph project with our Svelte applications and make queries.
Connecting Svelte with the Hygraph’s project GraphQL API We will first need to obtain our access URL to establish a connection between our application and the Hygraph GraphQL endpoint. To accomplish this, we will navigate to our Hygraph project and access Project Settings > ACCESS > API Access > Public Content API to configure our API permissions as illustrated below:
Following this, proceed to Project Settings > ACCESS > API Access > Endpoints, where you’ll obtain the Content API. Copy the “high-performance content API” and incorporate it as an environmental variable in your Svelte application for future use in GraphQL requests.
To achieve this, we will create a file named .env
and insert the following into it:
VITE_HYGRAPH_URL=add your url
Next, we will install graphql-request
into our Svelte application like so:
npm i graphql-request
Now, let‘s navigate to the routes>+page.svelte
and add the code below into our <script>
tag. This code fetches the product
, store
data from the Content API endpoint, populates the products
, and stores
variable.
<script>import "../app.css";import { onMount } from 'svelte';import { gql, GraphQLClient } from 'graphql-request';import ProductCard from '../components/ProductCard.svelte';export let products = [];export let stores = [];onMount(async () => {const hygraphURL = import.meta.env.VITE_HYGRAPH_URL;const client = new GraphQLClient(hygraphURL);const query = gql`query products {stores {citynameproducts {idimagenamepricedescription}}}`;try {const data = await client.request(query);stores = data.stores;} catch (error) {console.error('Error fetching data:', error);}});</script>
Now, let us break down what we achieved in the code block above:
Imports: The script imports necessary modules and dependencies. These include a CSS file (
app.css
), theonMount
function from Svelte, and thegql
andGraphQLClient
objects from thegraphql-request
library. Additionally, it imports theProductCard
component from the specified location.Exported variables: Two variables,
products
andstores
, were exported from the script. These variables will hold the fetched data.onMount hook: The
onMount
function is a Svelte lifecycle function that runs when the component is mounted to the DOM. Inside this hook, an asynchronous function is defined to fetch data from the GraphQL API.GraphQL client initialization: Within the asynchronous function, the script obtains the GraphQL API endpoint URL from the
.env
file usingimport.meta.env.VITE_HYGRAPH_URL
. It then initializes a new GraphQL client (client
) using this URL.GraphQL query: The script constructs a GraphQL query using the
gql
template literal. The query requests data forproducts
andstores
, specifying the fields to retrieve for each.Data fetching: The script requests the GraphQL API using the initialized client (
client.request(query)
). Upon receiving a response, the data forproducts
andstores
is extracted from the response.Data assignment: The fetched data is assigned to the
products
andstores
variables. This updates the variables with the retrieved data, making it available for use in the Svelte component.Error handling: If an error occurs during the data fetching process, it is caught and logged to the console using
console.error
.
Creating a card component
Next we’ll create a reusable Svelte component that displays the product details from the GraphQL request. To do that, we will create a file in src > components
named “ProductCard.svelte” and add the code below:
<script>export let product;</script><div class="bg-white rounded-lg overflow-hidden shadow-lg p-6 m-4"><img src={product.image} alt={product.name} class="w-full h-48 object-cover mb-4"><h2 class="text-xl font-semibold">{product.name}</h2><p class="text-gray-800">${product.price}</p><p class="text-sm text-gray-500">{product.description}</p></div>
Now, we will import this component for use into the src > routes > [+page.svelte]
like so:
import ProductCard from '../components/ProductCard.svelte';
To render each product, we will use the <ProductCard>
component by adding this just below the <script>
tag, like so:
<h1 class="text-3xl font-semibold mb-8">Product List</h1><div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">{#each stores as store}{#each store.products as product}<ProductCard {product} key={product.id} />{/each}{/each}</div>
Displaying the store
To display the data from the “stores” array as a table, we will add the code below:
<h1 class="text-3xl font-semibold mb-8">Stores</h1><table class="min-w-full divide-y divide-gray-200"><thead class="bg-gray-50"><tr><th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th><th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">City</th></tr></thead><tbody class="bg-white divide-y divide-gray-200">{#each stores as store}<tr><td class="px-6 py-4 whitespace-nowrap">{store.name}</td><td class="px-6 py-4 whitespace-nowrap">{store.city}</td></tr>{/each}</tbody></table>
In the code above, we used the {#each stores as store}
Svelte syntax to iterate over the "stores" array and created a table row for each store.
In the browser, we can see our Svelte application looking like this:
The complete code for the application above can be found here.
#Conclusion
This article explored Content Federation and its significance in modern application development. We walked through setting up a Hygraph project, leveraged the power of Hygraph's Content Federation capabilities to combine data from multiple sources seamlessly, and integrated a Svelte app with GraphQL for efficient data fetching.
There’s still a lot more to try out with Hygraph. By creating a free-forever account on Hygraph and exploring more instances of Federate This, you’ll gain a better understanding and hands-on experience of the Content Federation. The Hygraph Slack community is also a great place to share any challenge you may encounter while using Hygraph or chat with the Hygraph team.
Blog Author
Motunrayo Moronfolu
Senior Frontend Engineer and Technical writer passionate about building and writing about great user experiences.