Aller au contenu

Strapi & Astro

Strapi est un CMS Headless open-source et personnalisable.

Ce guide va construire une fonction wrapper pour connecter Strapi avec Astro.

Pour commencer, vous devez disposer des éléments suivants :

  1. Un projet Astro - Si vous n’avez pas encore de projet Astro, notre Guide d’installation vous permettra d’être opérationnel en un rien de temps.
  2. Un serveur CMS Strapi - Vous pouvez configurer un serveur Strapi dans un environnement local.

Pour ajouter votre URL Strapi à Astro, créez un fichier .env à la racine de votre projet (s’il n’existe pas déjà) et ajoutez la variable suivante :

.env
STRAPI_URL="http://127.0.0.1:1337" # ou utilisez votre adresse IP

Vous pouvez maintenant utiliser cette variable d’environnement dans votre projet Astro.

Si vous voulez avoir IntelliSense pour votre variable d’environnement, vous pouvez créer un fichier env.d.ts dans le répertoire src/ et configurer ImportMetaEnv comme ceci :

src/env.d.ts
interface ImportMetaEnv {
readonly STRAPI_URL: string;
}

Votre répertoire racine devrait maintenant contenir le(s) nouveau(x) fichier(s) :

  • Répertoiresrc/
  • env.d.ts
  • .env
  • astro.config.mjs
  • package.json

Créez un nouveau fichier src/lib/strapi.ts et ajoutez la fonction wrapper suivante pour interagir avec l’API Strapi :

src/lib/strapi.ts
interface Props {
endpoint: string;
query?: Record<string, string>;
wrappedByKey?: string;
wrappedByList?: boolean;
}
/**
* Récupère les données de l'API Strapi
* @param endpoint - Le point d'accès à partir duquel la recherche doit être effectuée
* @param query - Les paramètres de requête à ajouter à l'URL
* @param wrappedByKey - La clé pour décapsuler la réponse
* @param wrappedByList - Si la réponse est une liste, déroulez-la.
* @returns
*/
export default async function fetchApi<T>({
endpoint,
query,
wrappedByKey,
wrappedByList,
}: Props): Promise<T> {
if (endpoint.startsWith('/')) {
endpoint = endpoint.slice(1);
}
const url = new URL(`${import.meta.env.STRAPI_URL}/api/${endpoint}`);
if (query) {
Object.entries(query).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
}
const res = await fetch(url.toString());
let data = await res.json();
if (wrappedByKey) {
data = data[wrappedByKey];
}
if (wrappedByList) {
data = data[0];
}
return data as T;
}

Cette fonction nécessite un objet ayant les propriétés suivantes :

  1. endpoint - Le point d’accès que vous récupérez.
  2. query - Les paramètres de requête à ajouter à la fin de l’URL
  3. wrappedByKey - La clé data dans l’objet qui enveloppe votre Response.
  4. wrappedByList - Un paramètre pour “déballer” la liste retournée par Strapi, et ne retourner que le premier élément.

Facultatif : Création de l’interface Article

Titre de la section Facultatif : Création de l’interface Article

Si vous utilisez TypeScript, créez l’interface Article suivante pour correspondre aux types de contenu Strapi dans src/interfaces/article.ts :

src/interfaces/article.ts
export default interface Article {
id: number;
attributes: {
title: string;
description: string;
content: string;
slug: string;
createdAt: string;
updatedAt: string;
publishedAt: string;
};
}
  • Répertoiresrc/
  • Répertoireinterfaces/
  • article.ts
  • Répertoirelib/
  • strapi.ts
  • env.d.ts
  • .env
  • astro.config.mjs
  • package.json
  1. Mettez à jour votre page d’accueil src/pages/index.astro pour afficher une liste d’articles de blog, chacun avec une description et un lien vers sa propre page.

  2. Importez la fonction wrapper et l’interface. Ajoutez l’appel API suivant pour récupérer vos articles et renvoyer une liste :

    src/pages/index.astro
    ---
    import fetchApi from '../lib/strapi';
    import type Article from '../interfaces/article';
    const articles = await fetchApi<Article[]>({
    endpoint: 'articles', // le type de contenu à récupérer
    wrappedByKey: 'data', // la clé pour décapsuler la réponse
    });
    ---

    L’appel API demande des données à http://localhost:1337/api/articles et renvoie articles : un tableau d’objets json représentant vos données :

    [
    {
    id: 1,
    attributes: {
    title: "Ce qu'il y a à l'intérieur d'un trou noir",
    description: "La réponse se trouve peut-être dans cet article, ou pas...",
    content: "Nous ne le savons pas encore...",
    slug: "what-s-inside-a-black-hole",
    createdAt: "2023-05-28T13:19:46.421Z",
    updatedAt: "2023-05-28T13:19:46.421Z",
    publishedAt: "2023-05-28T13:19:45.826Z"
    }
    },
    // ...
    ]
  3. En utilisant les données du tableau articles renvoyé par l’API, affichez les articles de votre blog Strapi dans une liste. Ces articles seront liés à leur propre page individuelle, que vous allez créer à l’étape suivante.

    src/pages/index.astro
    ---
    import fetchApi from '../lib/strapi';
    import type Article from '../interfaces/article';
    const articles = await fetchApi<Article[]>({
    endpoint: 'articles?populate=image',
    wrappedByKey: 'data',
    });
    ---
    <!DOCTYPE html>
    <html lang="fr">
    <head>
    <title>Strapi & Astro</title>
    </head>
    <body>
    <main>
    <ul>
    {
    articles.map((article) => (
    <li>
    <a href={`/blog/${article.attributes.slug}/`}>
    {article.attributes.title}
    </a>
    </li>
    ))
    }
    </ul>
    </main>
    </body>
    </html>

Créez le fichier src/pages/blog/[slug].astro pour générer dynamiquement une page pour chaque article.

  • Répertoiresrc/
  • Répertoireinterfaces/
  • article.ts
  • Répertoirelib/
  • strapi.ts
  • Répertoirepages/
  • index.astro
  • Répertoireblog/
  • [slug].astro
  • env.d.ts
  • .env
  • astro.config.mjs
  • package.json

Dans le mode statique par défaut d’Astro (SSG), utilisez getStaticPaths() pour récupérer votre liste d’articles à partir de Strapi.

"src/pages/blog/[slug].astro
---
import fetchApi from '../../lib/strapi';
import type Article from '../../interfaces/article';
export async function getStaticPaths() {
const articles = await fetchApi<Article[]>({
endpoint: 'articles',
wrappedByKey: 'data',
});
return articles.map((article) => ({
params: { slug: article.attributes.slug },
props: article,
}));
}
type Props = Article;
const article = Astro.props;
---

Créer le modèle pour chaque page en utilisant les propriétés de chaque objet post.

"src/pages/blog/[slug].astro
---
import fetchApi from '../../lib/strapi';
import type Article from '../../interfaces/article';
export async function getStaticPaths() {
const articles = await fetchApi<Article[]>({
endpoint: 'articles',
wrappedByKey: 'data',
});
return articles.map((article) => ({
params: { slug: article.attributes.slug },
props: article,
}));
}
type Props = Article;
const article = Astro.props;
---
<!DOCTYPE html>
<html lang="fr">
<head>
<title>{article.attributes.title}</title>
</head>
<body>
<main>
<img src={import.meta.env.STRAPI_URL + article.attributes.image.data.attributes.url} />
<h1>{article.attributes.title}</h1>
<!-- Rendre du texte brut -->
<p>{article.attributes.content}</p>
<!-- Rendre du markdown -->
<MyMarkdownComponent>
{article.attributes.content}
</MyMarkdownComponent>
<!-- Rendre du html -->
<Fragment set:html={article.attributes.content} />
</main>
</body>
</html>

Si vous avez opté pour le mode SSR (EN) avec output : server ou output : hybrid, générez vos routes dynamiques en utilisant le code suivant :

Créez le fichier src/pages/blog/[slug].astro :

src/pages/blog/[slug].astro
---
import fetchApi from '../../../lib/strapi';
import type Article from '../../../interfaces/article';
const { slug } = Astro.params;
let article: Article;
try {
article = await fetchApi<Article>({
endpoint: 'articles',
wrappedByKey: 'data',
wrappedByList: true,
query: {
'filters[slug][$eq]': slug || '',
},
});
} catch (error) {
return Astro.redirect('/404');
}
---
<!DOCTYPE html>
<html lang="fr">
<head>
<title>{article.attributes.title}</title>
</head>
<body>
<main>
<img src={import.meta.env.STRAPI_URL + article.attributes.image.data.attributes.url} />
<h1>{article.attributes.title}</h1>
<!-- Rendre du texte brut -->
<p>{article.attributes.content}</p>
<!-- Rendre du markdown -->
<MyMarkdownComponent>
{article.attributes.content}
</MyMarkdownComponent>
<!-- Rendre du html -->
<Fragment set:html={article.attributes.content} />
</main>
</body>
</html>

Ce fichier va récupérer et rendre les données de la page de Strapi qui correspondent au paramètre dynamique slug.

Puisque vous utilisez une redirection vers /404, créez une page 404 dans src/pages :

src/pages/404.astro
<html lang="fr">
<head>
<title>Non trouvé</title>
</head>
<body>
<p>Désolé, cette page n'existe pas.</p>
<img src="https://http.cat/404" />
</body>
</html>

Si l’article n’est pas trouvé, l’utilisateur sera redirigé vers cette page 404 et sera accueilli par un adorable chat.

Pour déployer votre site, consultez nos guides de déploiement et suivez les instructions de votre hébergeur préféré.

Si votre projet utilise le mode statique par défaut d’Astro, vous devrez configurer un webhook pour déclencher une nouvelle construction lorsque votre contenu change. Si vous utilisez Netlify ou Vercel comme hébergeur, vous pouvez utiliser sa fonctionnalité de webhook pour déclencher une nouvelle compilation à partir de Strapi.

Pour configurer un webhook dans Netlify :

  1. Allez dans le tableau de bord de votre site et cliquez sur Build & deploy.

  2. Sous l’onglet Continuous Deployment, trouvez la section Build hooks et cliquez sur Add build hook.

  3. Donnez un nom à votre webhook et sélectionnez la branche sur laquelle vous souhaitez déclencher la construction. Cliquez sur Save et copiez l’URL générée.

Pour configurer un webhook dans Vercel :

  1. Allez sur le tableau de bord de votre projet et cliquez sur Settings.

  2. Sous l’onglet Git, trouvez la section Deploy Hooks.

  3. Donnez un nom à votre webhook et indiquez la branche sur laquelle vous souhaitez déclencher la construction. Cliquez sur Add et copiez l’URL générée.

Suivez le guide Strapi webhooks pour créer un webhook dans votre panneau d’administration Strapi.

Plus de guides sur les CMS

Contribuer

Comment pouvons-nous vous aider ?

Créer une issue GitHub

Le moyen le plus rapide d'alerter notre équipe d'un problème.

Communauté