Skip to content
Back to Knowledge Hub
AI Engineering

Integrating Gemini 1.5 Pro into Web Applications: Streaming, Functions, & Schema Validation

A comprehensive guide to building production-grade server-side proxies for the Google GenAI SDK with structured response validation, token usage monitoring, and zero-latency SSE streaming.

Bhuvanesh Jujare
Bhuvanesh Jujare

Final-Year CS Student & Full-Stack / AI Developer

Published 2026-07-26
Updated 2026-07-29
8 min read
3,840 reads
Integrating Gemini 1.5 Pro into Web Applications: Streaming, Functions, & Schema Validation

The @google/genai SDK introduces lightweight model aliases (`gemini-2.5-flash`, `gemini-1.5-pro`) and native responseSchema enforcement. However, embedding API keys directly into client JavaScript poses a high security risk. Here is how to construct a robust Express + Node server proxy.

#Why Gemini Proxy Servers Are Mandatory

Security Imperative

Never expose process.env.GEMINI_API_KEY in Vite client builds. Always route requests through a secure server endpoint (/api/ai/generate) to protect credentials and enforce rate limits.

#Server-Sent Events (SSE) Streaming

Streaming chunks directly from Gemini to the React frontend eliminates perceived latency for long multi-paragraph responses:

server/routes/ai.ts
typescript
1400 font-semibold">import { Router } 400 font-semibold">from 400 font-semibold">class="text-emerald-300">"express";
2400 font-semibold">import { GoogleGenAI } 400 font-semibold">from 400 font-semibold">class="text-emerald-300">"@google/genai";
3
4400 font-semibold">const router = 300 font-medium">Router();
5400 font-semibold">const ai = 400 font-semibold">new 300 font-medium">GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
6
7router.300 font-medium">post(400 font-semibold">class="text-emerald-300">"/api/ai/stream", 400 font-semibold">async (req, res) => {
8 400 font-semibold">const { prompt } = req.body;
9
10 res.300 font-medium">setHeader(400 font-semibold">class="text-emerald-300">"Content-Type", 400 font-semibold">class="text-emerald-300">"text/event-stream");
11 res.300 font-medium">setHeader(400 font-semibold">class="text-emerald-300">"Cache-Control", 400 font-semibold">class="text-emerald-300">"no-cache");
12 res.300 font-medium">setHeader(400 font-semibold">class="text-emerald-300">"Connection", 400 font-semibold">class="text-emerald-300">"keep-alive");
13
14 400 font-semibold">try {
15 400 font-semibold">const responseStream = 400 font-semibold">await ai.models.300 font-medium">generateContentStream({
16 model: 400 font-semibold">class="text-emerald-300">"gemini-2.5-flash",
17 contents: prompt,
18 });
19
20 400 font-semibold">for 400 font-semibold">await (400 font-semibold">const chunk of responseStream) {
21 400 font-semibold">if (chunk.text) {
22 res.300 font-medium">write(`data: ${JSON.300 font-medium">stringify({ text: chunk.text })}
23
24`);
25 }
26 }
27 res.300 font-medium">write("data: [DONE]
28
29");
30 res.300 font-medium">end();
31 } 400 font-semibold">catch (error: 300 font-medium">any) {
32 res.300 font-medium">status(500).300 font-medium">json({ error: error.message });
33 }
34});

#Type-Safe Function Calling Pattern

Gemini can trigger function calls based on user prompts. Here is how to register tools for live data retrieval:

server/aiTools.ts
typescript
1400 font-semibold">const weatherTool = {
2 name: 400 font-semibold">class="text-emerald-300">"getWeather",
3 description: 400 font-semibold">class="text-emerald-300">"Get real-time weather metrics 400 font-semibold">for a target city",
4 parameters: {
5 400 font-semibold">type: 400 font-semibold">class="text-emerald-300">"OBJECT",
6 properties: {
7 city: { 400 font-semibold">type: 400 font-semibold">class="text-emerald-300">"STRING", description: 400 font-semibold">class="text-emerald-300">"City name e.g. San Francisco" },
8 },
9 required: [400 font-semibold">class="text-emerald-300">"city"],
10 },
11};
12
13400 font-semibold">const response = 400 font-semibold">await ai.models.300 font-medium">generateContent({
14 model: 400 font-semibold">class="text-emerald-300">"gemini-2.5-flash",
15 contents: 400 font-semibold">class="text-emerald-300">"What is the current temperature in Seattle?",
16 config: {
17 tools: [{ functionDeclarations: [weatherTool] }],
18 },
19});
FINAL CHAPTER
LET'S BUILD THE FUTURE.

Always Learning. Always Building.

Available for Software Engineering • AI Engineering • Full Stack Development
GitHub
LinkedIn
Resume
Email
zsh - status.sh
BHUVANESH

Final-year Computer Science student building web applications, exploring applied AI, and turning concepts into real-world projects with clean code and care.

India

QUICK LINKS

Designed & Engineered by Bhuvanesh Jujare

Crafted with curiosity, consistency, and clean engineering.

© 2026 Bhuvanesh Jujare