How to fetch content data from Craft CMS using GraphQL.
By implementing the support for Craft’s Element API JSON data, we’ve already done a lot of the leg work for GraphQL support. There are some code changes we have to make but we can reuse the same components for fetching entries that we’ve already built.
To follow along with this video, you will need to clone and run the house-quest-craft project. Setting up this project is covered in the previous video.
Complete EntriesFetch.astro
component:
export async function getEntries(query: string) {
const url = "http://localhost:8888/api/";
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: query,
}),
});
let json = await response.json();
return json.data.entries;
}
Complete EntryFetch.astro
component:
---
export async function getEntry(query: string) {
const url = "http://localhost:8888/api";
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: query,
}),
});
let json = await response.json();
return json.data.entry;
}
---
Complete MarketNews.astro
component:
---
import { getEntries } from '../components/EntriesFetch.astro';
let query = `{
entries(sectionId: 12, limit: 3) {
id
title
slug
postDate
... on marketNews_default_Entry {
summaryText
}
}
}
`;
let marketNewsEntries = await getEntries(query);
---
<div class="bg-secondary pt-16 pb-20 px-4 sm:px-6 lg:pt-24 lg:pb-28 lg:px-8 border-opacity-50 border-t-8 border-primary">
<div class="relative max-w-lg mx-auto lg:max-w-7xl">
<div>
<h2 class="text-3xl tracking-tight font-extrabold text-gray-900 sm:text-4xl">Market News</h2>
<p class="mt-3 text-xl text-gray-800 sm:mt-4">An expert view of what's happening in the local housing market.</p>
</div>
<div class="mt-6 grid gap-16 pt-12 lg:grid-cols-3 lg:gap-x-5 lg:gap-y-12">
{marketNewsEntries.map(entry => (
<div>
<a href={'/news/' + entry.slug} class="block mt-4">
<p class="text-xl font-semibold text-gray-900">{entry.title}</p>
<p class="mt-3 text-base text-gray-900">{entry.summaryText}</p>
</a>
</div>
))}
</div>
</div>
</div>
Complete [slug].astro
component:
---
import Layout from '../../layouts/Layout.astro';
import InteriorHeader from '../../components/InteriorHeader.astro';
import { getEntry } from '../../components/EntryFetch.astro';
import { getEntries } from '../../components/EntriesFetch.astro';
const { slug } = Astro.params;
let singleArticleQuery = `{
entry(sectionId: 12, slug: "${slug}") {
id
title
slug
... on marketNews_default_Entry {
summaryText
richText
}
}
}
`
let entry = await getEntry(singleArticleQuery);
export async function getStaticPaths() {
let allArticlesQuery = `
{
entries(sectionId: 12) {
id
title
slug
postDate
... on marketNews_default_Entry {
summaryText
richText
}
}
}
`
let entries = await getEntries(allArticlesQuery);
return entries.map(( entry: { slug: string }) => {
return {
params: { slug: entry.slug},
props: { entry: entry },
};
});
}
---
<Layout>
<InteriorHeader />
<div class="bg-white">
<div class="relative py-16 bg-tertiary overflow-hidden">
<div class="relative px-4 sm:px-6 lg:px-8">
<div class="mt-6 prose prose-slate prose-lg text-gray-500 mx-auto">
<h1>{entry.title}</h1>
<div set:html={entry.richText}></div>
<p><a href="/news">Back to News</a></p>
</div>
</div>
</div>
</div>
</Layout>
Complete index.astro
(homepage) component:
---
import Layout from "../layouts/Layout.astro";
import { getEntry } from "../components/EntryFetch.astro";
import MarketNews from "../components/MarketNews.astro";
let query = `
{
entry(section: "homepage") {
title
id
... on homepage_homepage_Entry {
richText
}
}
}
`
let homepageContent = await getEntry(query);
---
<Layout title="Welcome Home">
<div class="bg-white">
<div class="max-w-full mx-auto py-16 px-4 sm:py-24 sm:px-6 lg:px-8 bg-primary shadow-2xl shadow-secondary border-opacity-50 border-b-8 border-secondary">
<div class="text-center">
<img
class="mx-auto h-40 w-40 rounded-full xl:w-56 xl:h-56 shadow-xl shadow-gray-500"
src="/images/omar-lopez-Gx5-zf_HE9w-unsplash.jpg"
alt=""
/>
<p
class="mt-1 text-4xl font-extrabold text-gray-900 sm:text-5xl sm:tracking-tight lg:text-6xl"
>
Olivia Lopez, CRS
</p>
<p class="max-w-xl mt-5 mx-auto text-xl text-gray-800">
In a competitive market, Olivia is the <strong>experienced real estate agent</strong> you want
on your side.
</p>
</div>
</div>
<div class="relative py-16 bg-tertiary overflow-hidden">
<div class="relative px-4 sm:px-6 lg:px-8">
<div class="mt-6 prose prose-indigo prose-lg text-gray-500 mx-auto">
<div set:html={homepageContent.richText} />
</div>
</div>
</div>
<MarketNews />
</div>
</Layout>
Astro Quick-Start Guide is made up of the following videos: