← Return to Blog / Thoughts

Integrating FastAPI with Next-Gen Vue/Nuxt Interfaces

2026-04-287 min
FastAPINuxtTypeScriptPythonAPI

Most portfolio sites gloss over the API boundary — the messy strip of no-man's-land between a Python backend and a JavaScript frontend. In production, that seam is where bugs live. This post is about closing it properly.

Why FastAPI

FastAPI is the right tool for this job for two reasons: it generates an OpenAPI spec out of the box, and its Pydantic models give you runtime validation for free. The spec becomes your single source of truth for the interface contract.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class DeploymentPayload(BaseModel):
    service_name: str
    image_tag: str
    replicas: int = 1

@app.post("/deployments", response_model=DeploymentPayload)
async def create_deployment(payload: DeploymentPayload):
    # schedule the deployment...
    return payload

The response_model annotation is the key — FastAPI will serialize exactly what you declare, and nothing more. No accidental data leaks.

Type Generation on the Nuxt Side

Once the OpenAPI spec exists at http://localhost:8000/openapi.json, use openapi-typescript to generate TypeScript types:

$ npx openapi-typescript http://localhost:8000/openapi.json -o src/types/api.ts

Now your Nuxt composable can be fully typed with zero manual interface definitions:

import type { components } from '~/types/api'

type Deployment = components['schemas']['DeploymentPayload']

export const useDeployments = () => {
  const list = ref<Deployment[]>([])

  const create = async (payload: Deployment) => {
    const data = await $fetch<Deployment>('/api/deployments', {
      method: 'POST',
      body: payload,
    })
    list.value.push(data)
  }

  return { list, create }
}

If the backend changes a field name, TypeScript will scream at you at compile time rather than letting a runtime mismatch slip to production.

CORS and the Proxy Pattern

Never expose your Python backend directly to the browser in production. Run Nuxt's built-in server as a reverse proxy instead:

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/api/**': {
      proxy: { to: 'http://fastapi-service:8000/**' },
    },
  },
})

This collapses the cross-origin problem entirely — the browser sees one origin, and your FastAPI service never needs a CORS header.

What's Next

The next evolution here is adding a message queue between the two services. For long-running tasks (deployments, report generation), returning a job ID and polling via a Nuxt server-sent-event endpoint beats blocking HTTP every time.