Hashnode Loader with Astro 5
Install
graphql-request
npm install graphql-request yarn add graphql-request pnpm add graphql-request
Create file
src/loaders/hashnode/schemas.ts
withimport { z } from "astro/zod"; export const PostSchema = z.object({ 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 PostsDataSchema = z.object({ 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({ publication: z.object({ title: z.string(), post: PostSchema, }), }) export type Post = z.infer<typeof PostSchema> export type PostsData = z.infer<typeof PostsDataSchema> export type PostData = z.infer<typeof PostDataSchema>
Create file
src/loaders/hashnode/queries.ts
withimport { gql, GraphQLClient } from 'graphql-request'; import type { PostsData, PostData } from './schemas'; const getClient = () => new GraphQLClient('https://gql.hashnode.com'); export const getPosts = async (myHashnodeURL:string) => { const client = getClient(); const allPosts = await client.request<PostsData>( gql` query allPosts { publication(host: "${myHashnodeURL}") { title posts(first: 20) { pageInfo{ hasNextPage endCursor } edges { node { author{ name profilePicture } title subtitle brief slug coverImage { url } tags { name slug } publishedAt readTimeInMinutes } } } } } `, ); return allPosts; };
Create file
src/loaders/hashnode/loaders.ts
withimport { PostSchema } from './schemas'; import type { Loader } from 'astro/loaders'; import { getPosts } from './queries'; export interface HashnodePostsLoaderOptions { myHashnodeURL: string; } export function hashnodePostsLoader({ myHashnodeURL }: HashnodePostsLoaderOptions): Loader { return { name: 'hasnode-posts-loader', load: async ({ logger, parseData, store }) => { logger.info(`Loading posts from ${myHashnodeURL}`); const result = await getPosts(myHashnodeURL); for (const post of result.publication.posts.edges) { const data = post.node; store.set({ id: data.slug, data }); } logger.info(`Loaded ${result.publication.posts.edges.length} posts from ${myHashnodeURL}`); }, schema: () => PostSchema, }; }
Create file
src/content/config.ts
withimport { defineCollection } from 'astro:content' import { hashnodePostsLoader } from '../loaders/hasnode/loaders'; const myHashnodeURL = 'gelinjo.hashnode.dev' const posts = defineCollection({ loader: hashnodePostsLoader({myHashnodeURL}) }); export const collections = { posts }
Display on your Astro page like
--- import { getCollection } from 'astro:content'; const posts = await getCollection('posts'); --- posts.map((post) => ( <div> <h2>{post.data.title}</h2> <p>{post.data.brief}</p> <img src={post.data.coverImage.url} alt={post.data.title} /> <a href={`https://gelinjo.hashnode.dev/${post.data.slug}`}>Read more</a> </div> ))
Resources
Subscribe to my newsletter
Read articles from Jonathan Gelin directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Jonathan Gelin
Jonathan Gelin
Who am I? Whether it's as a Software Engineer, Tech Lead, or Architect, if it involves software development, I'm in! My journey began in the realm of Java development, but I fully transitioned into the universe of JavaScript/TypeScript and its exciting toolset. I support companies through their software development cycle challenges by utilizing Nx monorepos, micro frontends, robust testing strategies, and a touch of Extreme Programming philosophy. Every day for me is like waiting for the next episode of my favorite series—filled with learning, sharing, and growing together. Indeed, I'm as passionate about coaching and sharing knowledge as I am about coding. I am the father of two incredible boys, and I am endlessly grateful to my wife for supporting my passion every day.