There's a common problem in modern web development: you have structured data — JSON from a CMS, a database, or a configuration file — and you need to turn it into fully-rendered, styled web pages dynamically. Most solutions either lock you into a specific CMS or require a lot of glue code across disconnected systems.
So I built PageForge API — a full-stack page generation engine that takes structured JSON input and forges dynamic, styled web pages through a clean API-first architecture. Here's how it works and why I made the architectural choices I did.
The Problem: Structured Data → Web Pages
Imagine you're building a platform where clients need unique landing pages, product pages, or documentation pages generated from configuration data. Hard-coding templates doesn't scale. A headless CMS is overkill. What you need is a programmable, API-driven page forge.
PageForge API solves this by acting as a bridge: you send it JSON, it returns rendered pages.
Architecture Overview
The project is split into two distinct layers that communicate cleanly:
| Layer | Technology | Responsibility |
|---|---|---|
| Backend | FastAPI (Python) | Data ingestion, processing, template logic |
| Frontend | Next.js (TypeScript) | Page rendering, routing, client-side display |
| Data | JSON schemas | Input contracts for page structures |
The backend handles all the heavy lifting — validation, data normalization, template selection, and response construction. The frontend consumes the processed output and renders it via Next.js's hybrid rendering capabilities (SSR + CSR depending on the use case).
Repository Structure
page-forge-api/
├── fastapi/ # Python backend — core API logic
├── nextjs/ # TypeScript frontend — rendering layer
├── forge-data.json # Sample forged page data
├── input-data.json # Example input schema
├── new-sample.json # Additional test fixtures
└── sample-data.json # Reference data structures
The multiple JSON fixture files aren't just test data — they demonstrate the range of input schemas the engine is designed to handle. Real-world page generators need to be resilient to varied input shapes.
The FastAPI Backend
FastAPI was the natural choice here for several reasons:
- Automatic OpenAPI docs — as soon as you define your Pydantic models, you get interactive API documentation for free.
- Type safety from day one — Pydantic models enforce your input schema contract, so malformed data is rejected at the boundary, not deep inside your logic.
- Async-first — if the engine needs to fetch external resources or call downstream services, async handlers ensure the server stays non-blocking.
The backend receives JSON input representing a page definition, validates it against a schema, applies transformation logic, and returns a structured response that the frontend can render.
The Next.js Frontend
Next.js sits at the frontend layer and handles rendering. The key design decision here was keeping the frontend dumb — it doesn't make business logic decisions. It receives processed data from the API and maps it to components.
This decoupling is powerful because:
- You can swap the rendering layer without touching backend logic
- The API can serve multiple frontends or even mobile clients
- Testing is clean — you can unit test the API independently of rendering
TypeScript (93.4% of the codebase) ensures that data contracts between the API response and frontend components are enforced at compile time.
The Data Layer: JSON Contracts
The most interesting design problem in a page generation engine is the input schema. Too rigid and it's unusable. Too flexible and validation becomes a nightmare.
PageForge solves this with layered JSON schemas — a base contract all inputs must satisfy, with optional extension fields for more complex page types. Here's a simplified conceptual structure:
{
"pageType": "landing | product | docs",
"meta": {
"title": "string",
"description": "string",
"slug": "string"
},
"sections": [
{
"type": "hero | features | cta | content",
"data": {}
}
]
}
The backend validates this structure, resolves any references, applies defaults, and returns a fully-resolved page object ready to render.
Why API-First Page Generation Matters
The API-first approach to page generation is increasingly relevant as teams move toward:
- Programmatic content generation at scale
- AI-driven page creation pipelines
- Multi-channel publishing from a single data source
- Headless architectures where the rendering layer is replaceable
PageForge is a great foundation if you're building a white-label page generator, an AI-assisted website builder, or any system where page structure is driven by data rather than manual design.
Running It Locally
# Clone the repo
git clone https://github.com/candidateconnectt/page-forge-api
# Backend setup
cd fastapi
pip install -r requirements.txt
uvicorn main:app --reload
# Frontend setup (new terminal)
cd ../nextjs
npm install
npm run dev
What's Next
Some natural extensions I'm considering for this engine:
- AI-powered section generation — pass a prompt, get a page section back
- Template versioning and A/B testing support
- Webhook support for triggering page regeneration on data changes
- Export to static HTML for edge deployment
Resources
If you're building anything similar — headless page builders, dynamic content engines, or API-first web tools — I'd love to hear about your approach in the comments. And if this was useful, a ⭐ on GitHub goes a long way!
Built by Sameer Shah — AI & Full-Stack Developer | Portfolio
Top comments (0)