Github: https://github.com/cherylli/devto-api-nextjs
codesandbox: https://codesandbox.io/p/github/cherylli/devto-api-nextjs/main
We will create a basic app to pull articles from dev.to API, using next.js static site generation (SSG) and display the article when clicked into it.
Dev.to API documentation can be found [here].(https://developers.forem.com/api)
The endpoint to retrieve all posts from a user ishttps://dev.to/api/articles?username={username}
where the username can be a personal account or an organisation account name.
For example, the api endpoint to fetch all my articles is https://dev.to/api/articles?username=cherylli
the result looks like this,
Using SSG, we fetch all the posts in getStaticProps(),
//pages/index.js
export async function getStaticProps(){
const res = await fetch('https://dev.to/api/articles?username=cherylli')
const posts = await res.json()
return{
props:{
posts
},
}
}
Props will be generate on build, passing the props into the page component, and display them on the page
//pages/index.js
const Home = ({posts}) => {
return (
<main className={styles.container}>
<h1>
Dev.to Blog
</h1>
<p>
displaying dev.to blog posts using the Dev.to API
</p>
<div className={styles.grid}>
{posts.map((post) => (
<BlogPostCard post={post} key={post.id}/>
))}
</div>
</main>)
}
Single Article page
The article body is not included in the above endpoint. So we will need to use another endpoint to get the article content.
If a user also publishes to an organization, https://dev.to/api/articles?username={username}
returns all articles (including any articles published to an organization by the user). We will then need to specify username or organization when using the single article endpoint https://dev.to/api/articles/{username/organization}/{slug}
.
For example, this gets the article I published to the organization 'wdp'.
https://dev.to/api/articles/wdp/using-google-fonts-with-nextjs-typescript-4pba
If the user do not publish to an organization account, or we only want to retrieve articles published to an organization account using slug would be enough, as {username} can just be defaulted to the user or organisation name.
Clicking on the title in the card will navigate to post/{user}/{slug} using next.js dynamic routes
<Link href={`posts${post.path}`}>{post.title}</Link>
Since this is a dynamic route, we will also need getStaticPaths()
//pages/posts/[user]/[slug].js
export async function getStaticPaths() {
const res = await fetch(`https://dev.to/api/articles?username=cherylli`);
const posts = await res.json()
return {
paths: posts.map(post => ({
params: {
user: post.path.split('/')[0],
slug: post.slug
}
})),
fallback: 'blocking',
};
}
it fetches all my articles and returns user, and slug params, since I blog on both my personal and an organization account, the user param will vary based on where I published the article.
We can use these params in getStaticProps() to retrieve the single article,
//pages/posts/[user]/[slug].js
export const getStaticProps = async ({params}) => {
const res = await fetch(`https://dev.to/api/articles/${params.user}/${params.slug}`);
const post = await res.json()
return {
props: {
post
},
revalidate: 30
};
};
Now post can be passed into the page component, and post.body_html
is the body of the post in html.
//pages/posts/[user]/[slug].js
const BlogPage = ({post}) => {
return (
<div className={styles.container}>
// add content using the post props, and style the page
<div dangerouslySetInnerHTML={{ __html: post.body_html }} />
</div>
);
};
Notes
Using ID instead of Slug
We can also use the article id instead of slug, the endpoint would be https://dev.to/api/articles/{articleId}
. This simplifies the code since we do not have to worry about whether the article is published to a personal account or an organization account. The single article page url would be /posts/{id} instead.
Using Incremental Static Generation (ISR)
Since SSG generates the pages on build time, newly published articles won't be added to the index page without a re-build. ISR can be used to create/update static pages after the site is built.
Top comments (0)