A Complete, Runnable Small - Scale Solution: Front - End with Vue3 Mock Data and Back - End with API Gateway Integration

A Complete, Runnable Small - Scale Solution: Front - End with Vue3 Mock Data and Back - End with API Gateway Integration
Photo by Seoin Kim / Unsplash

Of course. Here is a complete, runnable, small-scale solution that demonstrates the entire architecture you've described.

This solution is divided into three distinct parts, which you will run simultaneously:

  1. Mock Native API (mock-native-api): A simple Python server that simulates a slow, external API returning a large JSON payload.
  2. API Gateway (backend-gateway): A Python FastAPI server that acts as our managed interface. It calls the Mock API.
  3. Frontend (frontend-vue): A Vue 3 application that allows a user to invoke the endpoints through our API Gateway.

Core Concepts Demonstrated

  • Abstraction: The gateway hides the messy details of the "native" API.
  • Management: The gateway provides clean, documented endpoints. We will see how it can transform data.
  • Large JSON Handling: We'll demonstrate two strategies:
    1. Proxying the large data directly (inefficient).
    2. Creating a summary endpoint where the gateway processes the large data and returns a small, useful payload (the Backend-for-Frontend pattern).

Step 1: Project Structure

First, create a parent directory for the project and set up the following structure.

mkdir api-gateway-solution && cd api-gateway-solution

# Create directories for each part of the application
mkdir mock-native-api
mkdir backend-gateway
mkdir frontend-vue

Your final structure will look like this:

api-gateway-solution/
├── mock-native-api/
│   └── main.py
│   └── requirements.txt
├── backend-gateway/
│   └── main.py
│   └── requirements.txt
└── frontend-vue/
    └── (Vue 3 project files)

Step 2: Create the Mock Native API

This service simulates a slow, third-party API that we don't control.

Create main.py: This server will listen on port 8001. It has one endpoint /data that takes 2 seconds to respond and returns a large array of 500 fake users.

# mock-native-api/main.py
import asyncio
from fastapi import FastAPI
from faker import Faker
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()
fake = Faker()

# Allow CORS so our gateway (on a different port) can call it
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"], # In production, restrict this to your gateway's address
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/data")
async def get_large_json_data():
    """
    Simulates a slow endpoint that returns a large amount of data.
    """
    print("Mock Native API: Received request. Simulating 2-second delay...")
    await asyncio.sleep(2) # Simulate slow database/processing

    print("Mock Native API: Generating and sending large payload.")
    payload = [
        {
            "id": i,
            "name": fake.name(),
            "email": fake.email(),
            "profile": {
                "job": fake.job(),
                "company": fake.company(),
                "address": fake.address().replace("\n", ", "),
                "bio": fake.paragraph(nb_sentences=5),
            },
            "last_login": str(fake.iso8601()),
        }
        for i in range(500)
    ]
    return payload

Create requirements.txt:

fastapi
uvicorn
Faker

Navigate to the directory:

cd mock-native-api

Step 3: Create the Python API Gateway

This is our managed layer. It will expose clean endpoints to the front-end.

Create main.py: This server will listen on port 8000. It calls the Mock API on port 8001.

# backend-gateway/main.py
import httpx
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware

# Configuration
MOCK_API_BASE_URL = "http://localhost:8001"

app = FastAPI(
    title="Managed API Gateway",
    description="Provides a clean, monitored, and managed interface for external services."
)

# Allow CORS for our Vue frontend (running on port 5173)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5173"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/api/v1/users/full")
async def get_all_user_data_inefficient():
    """
    Endpoint that proxies the entire large payload.
    This is memory-inefficient for the gateway.
    """
    print("GATEWAY: Received request for FULL data. Calling mock service...")
    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(f"{MOCK_API_BASE_URL}/data", timeout=10.0)
            response.raise_for_status()
            print("GATEWAY: Success. Forwarding full payload to client.")
            return response.json()
        except httpx.RequestError as e:
            raise HTTPException(status_code=502, detail=f"Bad Gateway: Error calling native service - {e}")


@app.get("/api/v1/users/summary")
async def get_user_summary_efficient():
    """
    Endpoint that fetches large data, processes it, and returns a small summary.
    This is the efficient Backend-for-Frontend (BFF) pattern.
    """
    print("GATEWAY: Received request for SUMMARY data. Calling mock service...")
    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(f"{MOCK_API_BASE_URL}/data", timeout=10.0)
            response.raise_for_status()
            large_data = response.json()

            print("GATEWAY: Success. Processing large payload to create summary.")
            summary = {
                "user_count": len(large_data),
                "user_names": [user["name"] for user in large_data[:10]] # Get first 10 names
            }
            print("GATEWAY: Sending small summary to client.")
            return summary
        except httpx.RequestError as e:
            raise HTTPException(status_code=502, detail=f"Bad Gateway: Error calling native service - {e}")

Create requirements.txt:

fastapi
uvicorn
httpx
python-dotenv

httpx is a modern async HTTP client, perfect for calling other APIs from FastAPI.

Navigate to the directory:

cd ../backend-gateway  # Go up one level and into the gateway directory

Step 4: Create the Vue 3 Frontend

This is the user interface to interact with our system.

Replace the contents of src/App.vue with the following: This creates the UI with two buttons to call our two gateway endpoints.

<script setup>
import { ref } from 'vue';
import axios from 'axios';

const loading = ref(false);
const error = ref(null);
const responseData = ref(null);
const startTime = ref(0);
const elapsedTime = ref(0);

const API_GATEWAY_URL = 'http://localhost:8000';

const fetchData = async (endpoint) => {
  loading.value = true;
  error.value = null;
  responseData.value = null;
  startTime.value = performance.now();

  try {
    const result = await axios.get(`${API_GATEWAY_URL}${endpoint}`);
    responseData.value = result.data;
  } catch (err) {
    error.value = err.response ? err.response.data.detail : err.message;
  } finally {
    loading.value = false;
    elapsedTime.value = ((performance.now() - startTime.value) / 1000).toFixed(2);
  }
};
</script>

<template>
  <main>
    <h1>API Gateway Demo</h1>
    <div class="controls">
      <button @click="fetchData('/api/v1/users/full')" :disabled="loading">
        Fetch Full Data (Slow & Inefficient)
      </button>
      <button @click="fetchData('/api/v1/users/summary')" :disabled="loading">
        Fetch Summary (Fast & Efficient)
      </button>
    </div>

    <div v-if="loading" class="status loading">
      <p>Loading... Please wait.</p>
    </div>

    <div v-if="error" class="status error">
      <h3>Error</h3>
      <p>{{ error }}</p>
    </div>

    <div v-if="responseData" class="results">
      <h3>Response Received (took {{ elapsedTime }} seconds)</h3>
      <pre>{{ JSON.stringify(responseData, null, 2) }}</pre>
    </div>
  </main>
</template>

<style>
:root { font-family: sans-serif; }
main { max-width: 800px; margin: 2rem auto; padding: 1rem; }
.controls { display: flex; gap: 1rem; margin-bottom: 1.5rem; }
button { font-size: 1rem; padding: 0.5rem 1rem; cursor: pointer; border-radius: 5px; border: 1px solid #ccc; }
button:disabled { cursor: not-allowed; opacity: 0.6; }
.status { padding: 1rem; border-radius: 5px; margin-top: 1rem; }
.loading { background-color: #e0e7ff; }
.error { background-color: #ffe4e6; color: #9f1239; }
.results { background-color: #f0fdf4; border: 1px solid #bbf7d0; padding: 1rem; border-radius: 5px; margin-top: 1rem; }
pre { white-space: pre-wrap; word-wrap: break-word; max-height: 400px; overflow-y: auto; background-color: #fff; padding: 1rem; }
</style>

Install axios for making HTTP requests:

npm install axios

Navigate to the frontend-vue directory and bootstrap a Vue 3 project using Vite:

cd ../frontend-vue
# Use npm, yarn, or pnpm. We'll use npm here.
npm create vite@latest . -- --template vue
# Follow the prompts. You can name your project `frontend-vue`.
# When done, install dependencies
npm install

Step 5: Running the Full Solution

You will need three separate terminal windows.

Terminal 1: Run the Mock Native API

cd /path/to/api-gateway-solution/mock-native-api

# Create a virtual environment (optional but recommended)
python -m venv venv
source venv/bin/activate  # On Windows use `venv\Scripts\activate`

# Install dependencies
pip install -r requirements.txt

# Run the server on port 8001
uvicorn main:app --host 0.0.0.0 --port 8001

Terminal 2: Run the API Gateway

cd /path/to/api-gateway-solution/backend-gateway

# Create a virtual environment
python -m venv venv
source venv/bin/activate  # On Windows use `venv\Scripts\activate`

# Install dependencies
pip install -r requirements.txt

# Run the server on port 8000
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

You can also visit http://localhost:8000/docs in your browser to see the auto-generated API documentation for your gateway!

Terminal 3: Run the Vue Frontend

cd /path/to/api-gateway-solution/frontend-vue

# Install dependencies if you haven't already
npm install

# Run the development server
npm run dev

Step 6: Test the Application

  1. Open your browser and navigate to the address shown in Terminal 3 (usually http://localhost:5173).
  2. Click "Fetch Full Data (Slow & Inefficient)":
    • Notice the UI says "Loading..." for over 2 seconds.
    • Watch the terminal output in Terminal 1 (Mock API) and Terminal 2 (Gateway). You'll see the request flow through.
    • After the delay, the huge JSON payload will be displayed in the browser.
  3. Click "Fetch Summary (Fast & Efficient)":
    • The backend process is still slow (it has to wait 2 seconds for the mock API), but the data returned to the frontend is tiny.
    • The total time will still be ~2 seconds, but you'll see a small, clean summary object. This demonstrates how the gateway protected the frontend from a heavy payload, saving browser memory and making the data easier to consume. In a real-world scenario with a faster native API, the summary endpoint would feel instantaneous.