Tickd.ai
← The Tickd Guide

Tutorials & Guides

How to Build a Local Mock API Server That Generates Dynamic Responses Using Gemini 1.5 Flash and Fastify

Frontend development shouldn't halt because the backend API isn't ready. Learn how to write a local Fastify server that generates real, schema-compliant mock data on the fly.

Updated 10/8/2026

We have all been there. The backend team promised that the user-service API endpoints would be finalized and ready to integrate by Tuesday. It is now Friday. You are staring at a blank UI screen because your state management library needs real JSON payloads to work, and you are tired of copy-pasting static mock files that fail to handle dynamic edge cases.

You could write manual mock endpoints in Express, but coding realistic state transitions, variable ID outputs, and structured array variations takes forever.

Instead, we can build a local mock server using Fastify and Gemini 1.5 Flash. When you call this mock server, it looks at the requested URL path, uses your defined typescript/JSON schemas to build a structured output request, and tasks Gemini with generating contextually relevant, realistic data on the fly. Thanks to Gemini's native structured outputs support, the returned JSON will always match your target schemas precisely.

Why Gemini 1.5 Flash for Mocking?

Dynamic mocking requires speed. If your local API mock takes four seconds to generate a response, the developer feedback loop breaks. Gemini 1.5 Flash is highly optimized for fast inference times and has incredibly low token costs, making it the perfect engine for local developer productivity tooling.

Additionally, its schema-conformance capability ensures that if your frontend code expects an object with an array of line_items where each item has a sku matching a specific pattern, Gemini will generate strings that accurately fit that mold.

Setup and Architecture

We will build this mock server using Node.js and Fastify. Create a new directory and initialize your project:

`bash mkdir gemini-mock-server cd gemini-mock-server npm init -y `

Install the required dependencies. We will use the official Google Gen AI SDK, Fastify, and Zod to declare our API schemas:

`bash npm install fastify @google/genai zod npm install -D typescript @types/node tsx `

Initialize TypeScript config:

`bash npx tsc --init `

Ensure you have your API key set up in your local environment variables:

`bash export GEMINI_API_KEY="your-gemini-api-key-here" `

Step 1: Defining Our Target Schemas

Rather than writing generic text prompts, we will use structured schemas. This ensures the output from the mock server is always valid and parseable by your application's API client.

Let's create a file named schemas.ts and define a schema for a user profile and an active e-commerce shopping cart:

`typescript import { z } from 'zod';

export const UserProfileSchema = z.object({ id: z.string().uuid(), username: z.string(), email: z.string().email(), role: z.enum(['admin', 'member', 'billing_manager']), preferences: z.object({ darkMode: z.boolean(), notificationsEnabled: z.boolean(), }), createdAt: z.string().datetime() });

export const CartSchema = z.object({ cartId: z.string(), items: z.array(z.object({ productId: z.string(), name: z.string(), quantity: z.number().int().min(1).max(5), priceInCents: z.number().int(), currency: z.string().length(3) })), discountApplied: z.boolean(), totalAmountCents: z.number().int() });

// We map our paths to schemas to help our router match requests dynamically export const routeRegistry: Record<string, any> = { '/api/v1/user/profile': UserProfileSchema, '/api/v1/cart/active': CartSchema }; `

Step 2: Creating the Gemini Generator

Next, we need to pass these schemas to the Gemini model. By transforming our Zod validation models into JSON Schema definitions, we can use the responseSchema configuration parameter in the Google Gen AI SDK to guarantee type-safe mock data.

Create generator.ts:

`typescript import { GoogleGenAI } from '@google/genai'; import { zodToJsonSchema } from 'zod-to-json-schema'; import { routeRegistry } from './schemas';

// Initialize the client. This SDK handles connection state cleanly. const ai = new GoogleGenAI();

export async function generateMockData(path: string, queryParams: Record<string, any>) { const schema = routeRegistry[path]; if (!schema) { throw new Error(No schema registered for path: ${path}); }

// Convert Zod to JSON Schema format expected by Gemini const jsonSchema = zodToJsonSchema(schema) as any;

const prompt = ` Generate a realistic mock API JSON response for the endpoint path: "${path}". Context and constraints: - Query Parameters passed: ${JSON.stringify(queryParams)} - Ensure strings represent realistic data (e.g., real names for usernames, proper emails, believable dates). - Make the generated data cohesive. If items are in a cart, the totalAmountCents must accurately equal the sum of item prices and quantities. `;

const response = await ai.models.generateContent({ model: 'gemini-1.5-flash', contents: prompt, config: { responseMimeType: 'application/json', responseSchema: jsonSchema, temperature: 0.7, // Add slight variation while maintaining structural sanity } });

if (!response.text) { throw new Error('Gemini failed to generate a response body.'); }

return JSON.parse(response.text); } `

Step 3: Setting Up the Fastify Server

Now, let's wire this up to a Fastify instance. Fastify is an ideal framework here because of its raw speed and straightforward routing configuration. We will configure a catch-all route handler that intercepts inbound requests, checks if we have a matching schema, and calls the mock generator.

Create server.ts:

`typescript import Fastify from 'fastify'; import { generateMockData } from './generator'; import { routeRegistry } from './schemas';

const fastify = Fastify({ logger: true });

// Handle CORS so your frontend application can fetch from this server seamlessly fastify.register(require('@fastify/cors'), { origin: '*' });

// Catch-all route to mock any endpoint we have registered fastify.all('*', async (request, reply) => { const url = new URL(request.url, 'http://localhost'); const path = url.pathname;

if (!routeRegistry[path]) { return reply.status(404).send({ error: 'Mock Schema Not Found', message: No mock schema defined for endpoint: ${path}. Register it in schemas.ts. }); }

try { const mockData = await generateMockData(path, request.query || {}); return reply.status(200).send(mockData); } catch (error: any) { fastify.log.error(error); return reply.status(500).send({ error: 'Failed to generate mock data', details: error.message }); } });

const start = async () => { try { await fastify.listen({ port: 3001 }); console.log('🚀 Gemini dynamic mock server is ticking over smoothly at http://localhost:3001'); } catch (err) { fastify.log.error(err); process.exit(1); } };

start(); `

Step 4: Testing Your Mock Server

Start your development server with tsx:

`bash npx tsx server.ts `

Open up your API client (or use cURL) to verify the mock data generation works dynamically. Send a request to get the user profile mock:

`bash curl http://localhost:3001/api/v1/user/profile `

Your mock API server will generate a response structured precisely like this:

`json { "id": "d3b07384-d113-4ec5-a581-209210283cfa", "username": "alex_dev99", "email": "alex.dev99@gmail.com", "role": "member", "preferences": { "darkMode": true, "notificationsEnabled": false }, "createdAt": "2023-11-20T14:48:00Z" } `

Now, test the active cart route, noting how Gemini calculates logical dependencies correctly:

`bash curl http://localhost:3001/api/v1/cart/active `

Every time you call the endpoint, you get unique, logically consistent, schema-valid data that doesn't feel like a lazy copy-paste job. If you hit roadblocks with model timeouts or authentication, dive into our curated troubleshooting guides at /platforms/gemini/articles to optimize your developer workflow.

geminifastifytypescriptapi-mockingbackend

Keep going

Build something with the prompt generator, decode the jargon in the glossary, or compare the tools on our platform deep-dives.