TL;DR: Learn how I integrated my Dev.to blogs into my React portfolio, tackled CORS errors, fixed API caching bugs, and fully automated the blog fetch using GitHub Actions and Node.
🎯 Goal
I wanted to showcase my Dev.to blog posts on my React-based portfolio, with these goals in mind:
- ✅ SEO-friendly (Google should index my blogs)
- ✅ Fast loading
- ✅ No CORS issues
- ✅ Fully automated updates
- ✅ Clean fallback if Dev.to is down
What started as a simple fetch turned into a deep integration journey — here's how I did it 👇
🛠️ Phase 1: The Naive Client-Side Fetch
At first, I simply fetched my blog posts from Dev.to using their public API like this:
js
useEffect(() => {
fetch('https://dev.to/api/articles?username=parshuram_singh')
.then(res => res.json())
.then(data => setBlogs(data));
}, []);
The Problems
- CORS errors in some browsers (like Brave)
- No SEO: Blogs were loaded after page render
- Unreliable: If Dev.to was down, my blog section broke
- Caching issue: The API returned different blog counts when logged in vs incognito
Phase 2: Vercel Serverless Function
Next, I moved the logic to a serverless function on Vercel:
// /api/getBlogs.js
export default async (req, res) => {
const response = await fetch(DEVTO_API_URL);
const data = await response.json();
res.status(200).json(data);
};
Pros
- Solved CORS issues
- Centralized logic
Cons
- Still a runtime fetch
- Still not SEO indexable
- Added function cold start time
Phase 3: Static File with Node Script
To make things fast, SEO-friendly, and bulletproof, I wrote a Node script to fetch blog data and save it as a static file:
// fetch-devto-blogs.js
const fs = require('fs'); // Import the 'fs' module
const fetch = require('node-fetch'); // Assuming node-fetch is installed for Node.js environments
async function fetchBlogs() {
const response = await fetch('[https://dev.to/api/articles?username=parshuram_singh](https://dev.to/api/articles?username=parshuram_singh)');
const blogs = await response.json();
fs.writeFileSync('./public/blogs.json', JSON.stringify(blogs, null, 2));
}
fetchBlogs();
Now, my React app loads from blogs.json during build:
const blogs = await fetch('/blogs.json').then(res => res.json());
Massive Wins:
- Static = super fast
- SEO-optimized
- No CORS
- Resilient (even if Dev.to is down)
Phase 4: API Caching Mystery
I hit a weird bug:
In some browsers, the URL with per_page=100 returned only 1 blog!
# Returned 1 blog in Brave (incognito)
curl "[https://dev.to/api/articles?username=parshuram_singh&per_page=100](https://dev.to/api/articles?username=parshuram_singh&per_page=100)"
# Returned 2 blogs in Chrome (logged in)
Turns out, Dev.to's API caches responses differently based on login state — yikes!
Fix: Remove per_page=100
Just drop the param, and Dev.to gives a correct full list:
const DEVTO_API_URL = '[https://dev.to/api/articles?username=parshuram_singh](https://dev.to/api/articles?username=parshuram_singh)';
Phase 5: GitHub Actions Automation
To keep the blog feed updated, I automated the Node script using GitHub Actions:
name: Fetch Dev.to Blogs
on:
push:
branches: [main]
workflow_dispatch: # Allows manual trigger
jobs:
fetch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '20'
- run: npm install node-fetch # Install node-fetch for the script
- run: node fetch-devto-blogs.js
- run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git add public/blogs.json
git commit -m "Update blogs.json" || echo "No changes" # Commit only if changes exist
git push
Final Result:
- On every push, blogs are auto-fetched
- No manual update needed
- Blazing fast blog section
- Fully SEO-optimized
Final Setup Recap
Area | Solution |
---|---|
Source | Dev.to API (username=...) |
Fetching | Node.js Script |
Hosting | Vercel |
Output | public/blogs.json |
Automation | GitHub Actions |
CORS Issues | Solved |
SEO Support | Static data |
API Bug (Dev.to) | Avoided per_page=100 param |
Lessons Learned
- Avoid runtime fetch for public data use static where possible
- Always test public APIs in multiple browsers (incognito too!)
- GitHub Actions are great for automating content workflows
- Static files are simple, reliable, and perfect for SEO
Final Thoughts
This blog chronicles a significant part of my journey in building a robust and efficient online portfolio. The insights gained from tackling CORS, optimizing for SEO, and automating content delivery have been invaluable.
If you're integrating Dev.to or any API into your site, I hope this real-world account saves you hours of debugging and helps you build a more resilient application.
Want to see this live? My portfolio is now up and running! Check it out:
My Portfolio
If this helped or you liked the journey feel free to leave a comment below.
Happy coding!
— Parshuram Singh
Top comments (0)