Project: Blog Reader With API
Introduction
This project builds a blog reader SPA that loads posts from a REST API—list with pagination, detail by slug, loading and error states, and Vue Router navigation. Connect to FastAPI REST CRUD, Django blog REST, or JSONPlaceholder for mock data.
Prerequisites
- Fetching API and CORS
- Vue Router Basics
- Composables
- TypeScript With Vue
- Backend API running or use JSONPlaceholder
Architecture
PostListView → GET /api/v1/posts?page=1
PostDetailView → GET /api/v1/posts/:slug
↑
usePosts / usePost composables
↑
api/client.ts (fetch wrapper)Types
src/types/post.ts:
Adapt fields to your backend schema.
API Client
src/api/client.ts:
Vite proxy (dev)—Fetching API and CORS:
// vite.config.ts — proxy /api → backend.env:
VITE_API_URL=Empty VITE_API_URL with proxy uses relative /api/... paths.
Composables
src/composables/usePosts.ts:
src/composables/usePost.ts:
JSONPlaceholder mock (no backend):
// Replace URL with:
// https://jsonplaceholder.typicode.com/posts?_limit=10
// Map id → slug in adapter if neededRoutes
src/router/index.ts:
{
path: "/posts",
name: "posts",
component: () => import("@/views/PostListView.vue"),
},
{
path: "/posts/:slug",
name: "post-detail",
component: () => import("@/views/PostDetailView.vue"),
props: true,
},PostListView
PostDetailView
CORS Checklist
| Dev setup | Config |
|---|---|
| Vite proxy | server.proxy in vite.config.ts |
| Direct API URL | Backend CORSMiddleware / Flask-CORS |
| Production | Same-site Nginx proxy or strict CORS origins |
Deliverables
- Post list loads from API with loading/error/empty states
- Click navigates to
/posts/:slug - Detail page shows title and body
- Pagination or “load more” works
- Refresh on detail URL works in production build (SPA fallback)
- Types match API response shape
Extensions
- Search query
?q=debounced withwatch - Markdown body with sanitized renderer
- Pinia cache for visited posts
- Admin dashboard project for write API
FAQ
Backend has no slug field?
Use id in route: /posts/:id and adjust composable.
Pagination shape differs?
Adapt PaginatedPosts type and query params to your OpenAPI spec.
FastAPI OpenAPI?
Generate types with openapi-typescript (optional advanced step).
404 on detail refresh?
Deploy with Nginx try_files—Build and Deploy.
Combine with PostgreSQL blog schema?
Align with PostgreSQL blog project table design.