DEV Community

Cover image for How I Integrated Dev.to Blogs into My Portfolio: From Client-Side CORS to Full GitHub Automation
Parshuram Singh
Parshuram Singh

Posted on • Edited on

How I Integrated Dev.to Blogs into My Portfolio: From Client-Side CORS to Full GitHub Automation

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));
}, []);

Enter fullscreen mode Exit fullscreen mode

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);
};

Enter fullscreen mode Exit fullscreen mode

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();

Enter fullscreen mode Exit fullscreen mode

Now, my React app loads from blogs.json during build:

const blogs = await fetch('/blogs.json').then(res => res.json());
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)';
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)