DEV Community

Sameer Shah
Sameer Shah

Posted on

I Built a Full-Stack Page Generation Engine with FastAPI + Next.js (And Here's the Architecture)

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

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": {}
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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

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)