Aller au contenu

Hashnode & Astro

Hashnode est un CMS hébergé qui vous permet de créer un blog ou une simple publication.

L’API Hashnode Public API est une API GraphQL qui vous permet d’interagir avec Hashnode. Ce guide utilise graphql-request, un client GraphQL minimal qui fonctionne bien avec Astro, pour apporter vos données Hashnode dans votre projet 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 site Hashnode - Vous pouvez créer un site personnel gratuit en visitant Hashnode.

Installez le paquet graphql-request en utilisant le gestionnaire de paquets de votre choix :

Fenêtre du terminal
npm install graphql-request

Ce guide utilise graphql-request, un client GraphQL minimal qui fonctionne bien avec Astro, pour apporter vos données Hashnode dans votre projet Astro.

  1. Un blog Hashnode
  2. Un projet Astro intégré avec le paquet graphql-request installé.

Cet exemple va créer une page d’index qui liste les articles avec des liens vers des pages individuelles générées dynamiquement.

  1. Pour récupérer les données de votre site avec le paquet graphql-request, créez un répertoire src/lib et créez deux nouveaux fichiers client.ts & schema.ts :

    • Répertoiresrc/
      • Répertoirelib/
        • client.ts
        • schema.ts
      • Répertoirepages/
        • index.astro
    • astro.config.mjs
    • package.json
  2. Initialisez une instance API avec le GraphQLClient en utilisant l’URL de votre site web Hashnode.

    src/lib/client.ts
    import { gql, GraphQLClient } from "graphql-request";
    import type { AllPostsData, PostData } from "./schema";
    export const getClient = () => {
    return new GraphQLClient("https://gql.hashnode.com")
    }
    const myHashnodeURL = "astroplayground.hashnode.dev";
    export const getAllPosts = async () => {
    const client = getClient();
    const allPosts = await client.request<AllPostsData>(
    gql`
    query allPosts {
    publication(host: "${myHashnodeURL}") {
    id
    title
    posts(first: 20) {
    pageInfo{
    hasNextPage
    endCursor
    }
    edges {
    node {
    id
    author{
    name
    profilePicture
    }
    title
    subtitle
    brief
    slug
    coverImage {
    url
    }
    tags {
    name
    slug
    }
    publishedAt
    readTimeInMinutes
    }
    }
    }
    }
    }
    `
    );
    return allPosts;
    };
    export const getPost = async (slug: string) => {
    const client = getClient();
    const data = await client.request<PostData>(
    gql`
    query postDetails($slug: String!) {
    publication(host: "${myHashnodeURL}") {
    id
    post(slug: $slug) {
    id
    author{
    name
    profilePicture
    }
    publishedAt
    title
    subtitle
    readTimeInMinutes
    content{
    html
    }
    tags {
    name
    slug
    }
    coverImage {
    url
    }
    }
    }
    }
    `,
    { slug: slug }
    );
    return data.publication.post;
    };
  3. Configurez schema.ts pour définir la forme des données renvoyées par l’API Hashnode.

    src/lib/schema.ts
    import { z } from "astro/zod";
    export const PostSchema = z.object({
    id: z.string(),
    author: z.object({
    name: z.string(),
    profilePicture: z.string(),
    }),
    publishedAt: z.string(),
    title: z.string(),
    subtitle: z.string(),
    brief: z.string(),
    slug: z.string(),
    readTimeInMinutes: z.number(),
    content: z.object({
    html: z.string(),
    }),
    tags: z.array(z.object({
    name: z.string(),
    slug: z.string(),
    })),
    coverImage: z.object({
    url: z.string(),
    }),
    })
    export const AllPostsDataSchema = z.object({
    id: z.string(),
    publication: z.object({
    title: z.string(),
    posts: z.object({
    pageInfo: z.object({
    hasNextPage: z.boolean(),
    endCursor: z.string(),
    }),
    edges: z.array(z.object({
    node: PostSchema,
    })),
    }),
    }),
    })
    export const PostDataSchema = z.object({
    id: z.string(),
    publication: z.object({
    title: z.string(),
    post: PostSchema,
    }),
    })
    export type Post = z.infer<typeof PostSchema>
    export type AllPostsData = z.infer<typeof AllPostsDataSchema>
    export type PostData = z.infer<typeof PostDataSchema>

La recherche via getAllPosts() renvoie un tableau d’objets contenant les propriétés de chaque article telles que :

  • title - le titre de l’article
  • brief - l’affichage HTML du contenu de l’article
  • coverImage.url - l’URL source de l’image vedette de l’article
  • slug - le nom de l’article.

Utilisez le tableau posts renvoyé par la recherche pour afficher une liste d’articles de blog sur la page.

src/pages/index.astro
---
import { getAllPosts } from '../lib/client';
const data = await getAllPosts();
const allPosts = data.publication.posts.edges;
---
<html lang="en">
<head>
<title>Astro + Hashnode</title>
</head>
<body>
{
allPosts.map((post) => (
<div>
<h2>{post.node.title}</h2>
<p>{post.node.brief}</p>
<img src={post.node.coverImage.url} alt={post.node.title} />
<a href={`/post/${post.node.slug}`}>Lire la suite</a>
</div>
))
}
</body>
</html>
  1. Créez la page src/pages/post/[slug].astro pour générer dynamiquement une page pour chaque post.

    • Répertoiresrc/
    • Répertoirelib/
      • client.ts
      • schema.ts
      • Répertoirepages/
        • index.astro
        • Répertoirepost/
          • [slug].astro
    • astro.config.mjs
    • package.json
  2. Importez et utilisez getAllPosts() et getPost() pour récupérer les données de Hashnode et générer des routes de pages individuelles pour chaque post.

    src/pages/post/[slug].astro
    ---
    import { getAllPosts, getPost } from '../../lib/client';
    export async function getStaticPaths() {
    const data = await getAllPosts();
    const allPosts = data.publication.posts.edges;
    return allPosts.map((post) => {
    return {
    params: { slug: post.node.slug },
    }
    })
    }
    const { slug } = Astro.params;
    const post = await getPost(slug);
    ---
  3. Créez le modèle pour chaque page en utilisant les propriétés de chaque objet post. L’exemple ci-dessous montre le titre de l’article et le temps de lecture, puis le contenu complet de l’article :

    src/pages/post/[slug].astro
    ---
    import { getAllPosts, getPost } from '../../lib/client';
    export async function getStaticPaths() {
    const data = await getAllPosts();
    const allPosts = data.publication.posts.edges;
    return allPosts.map((post) => {
    return {
    params: { slug: post.node.slug },
    }
    })
    }
    const { slug } = Astro.params;
    const post = await getPost(slug);
    ---
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title>{post.title}</title>
    </head>
    <body>
    <img src={post.coverImage.url} alt={post.title} />
    <h1>{post.title}</h1>
    <p>{post.readTimeInMinutes} mins de lecture</p>
    <Fragment set:html={post.content.html} />
    </body>
    </html>

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

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é