A Complete, Runnable Small - Scale Solution: Front - End with Vue3 Mock Data and Back - End with API Gateway Integration
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:
- Mock Native API (
mock-native-api): A simple Python server that simulates a slow, external API returning a large JSON payload. - API Gateway (
backend-gateway): A Python FastAPI server that acts as our managed interface. It calls the Mock API. - 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:
- Proxying the large data directly (inefficient).
- 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
- Open your browser and navigate to the address shown in Terminal 3 (usually
http://localhost:5173). - 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.
- 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.