Github Repo https://github.com/lsvekis/Google-Apps-Script-APIs-and-Gemini
In this project, your Hybrid AI Orchestrator pulls in real data from the web using APIs and then lets AI (local model + Gemini) interpret that data.
To do that, we need to understand one key tool:
UrlFetchApp— the Apps Script class that lets you call APIs.
In this lesson you’ll learn:
- What an API is (quick recap)
- How to call an API using
UrlFetchApp.fetch() - How to handle JSON responses
- How to add headers (for APIs that need them)
- How to use Script Properties to swap APIs without changing code
- How our
fetchDataFromApi_()helper fits into the bigger AI project
🔹 1. Quick Recap: What Is an API?
Think of an API as a URL that gives you data instead of a web page.
Example:
https://catfact.ninja/fact
If you open that in a browser, you’ll see JSON:
{
"fact": "Cats sleep 70% of their lives.",
"length": 34
}
With Apps Script, we can call that URL with UrlFetchApp.fetch() and get the same JSON in code — and then pass it to AI.
🔹 2. Your First API Call in Apps Script
Create a new Apps Script project, and in Code.gs try this:
function testCatFactApi() {
const url = 'https://catfact.ninja/fact';
const res = UrlFetchApp.fetch(url);
const text = res.getContentText(); // raw JSON string
Logger.log('Raw response: ' + text);
const data = JSON.parse(text); // convert JSON string → object
Logger.log('Cat fact: ' + data.fact);
}
Run testCatFactApi():
- Open Executions or View → Logs
- You should see a random cat fact
This is the basic pattern we’ll reuse:
UrlFetchApp.fetch(url)getContentText()JSON.parse(...)
🔹 3. Adding Headers (for APIs That Require Them)
Some APIs need extra info — for example, a header that says:
“I want JSON, not HTML”
The icanhazdadjoke API is like that.
Example: Calling icanhazdadjoke with Apps Script
function testJokeApi() {
const url = 'https://icanhazdadjoke.com/';
const options = {
method: 'get',
headers: {
Accept: 'application/json'
},
muteHttpExceptions: true
};
const res = UrlFetchApp.fetch(url, options);
const code = res.getResponseCode();
const body = res.getContentText();
Logger.log('Status: ' + code);
Logger.log('Body: ' + body);
if (code >= 200 && code < 300) {
const data = JSON.parse(body);
Logger.log('Joke: ' + data.joke);
}
}
🔍
headers: { Accept: 'application/json' }
tells the API: “Please respond with JSON.”
🔹 4. Using Script Properties to Configure the API URL
Instead of hard-coding the URL in your functions, you can store it in Script Properties.
That way:
- You can switch APIs (weather → cat facts → jokes)
- Without changing any code
- Perfect for demos & teaching
Step 1 – Add a Script Property
In Apps Script:
- Click the gear icon (Project Settings)
- Scroll to Script properties → Add script property
- Add:
- Name:
DATA_API_URL - Value: e.g.
https://catfact.ninja/fact
- Name:
Step 2 – Read It in Code
Here’s a reusable helper:
function fetchDataFromApi_() {
const props = PropertiesService.getScriptProperties();
const dataApiUrl = props.getProperty('DATA_API_URL');
if (!dataApiUrl) {
throw new Error('DATA_API_URL is not set in Script properties.');
}
const res = UrlFetchApp.fetch(dataApiUrl, { muteHttpExceptions: true });
const code = res.getResponseCode();
const body = res.getContentText();
if (code < 200 || code >= 300) {
return {
source: 'error',
status: code,
body
};
}
try {
return JSON.parse(body);
} catch (e) {
return {
source: 'error',
status: code,
body,
parseError: String(e)
};
}
}
Now, anywhere in your script, you can do:
function testDataApiProperty() {
const data = fetchDataFromApi_();
Logger.log(JSON.stringify(data, null, 2));
}
To switch APIs, just change DATA_API_URL in Script Properties — no code changes needed.
🔹 5. Plugging in Real Sample APIs
Here’s how to use the free APIs we talked about, all via DATA_API_URL.
✅ Option A — Weather (Open-Meteo)
DATA_API_URL:
https://api.open-meteo.com/v1/forecast?latitude=43.65107&longitude=-79.347015¤t_weather=true
Then:
function testWeather() {
const data = fetchDataFromApi_();
Logger.log(JSON.stringify(data, null, 2));
const cw = data.current_weather;
if (cw) {
Logger.log('Temperature: ' + cw.temperature + '°C');
Logger.log('Wind speed: ' + cw.windspeed + ' km/h');
}
}
✅ Option B — Cat Facts
DATA_API_URL:
https://catfact.ninja/fact
Then:
function testCatFact() {
const data = fetchDataFromApi_();
Logger.log('Cat fact: ' + data.fact);
}
✅ Option C — Bored API
DATA_API_URL:
https://www.boredapi.com/api/activity
Then:
function testBoredApi() {
const data = fetchDataFromApi_();
Logger.log('Activity: ' + data.activity);
Logger.log('Type: ' + data.type);
}
✅ Option D — Jokes (with Headers)
For icanhazdadjoke, you’ll likely want a dedicated version that includes headers, like:
function fetchDataFromApi_() {
const props = PropertiesService.getScriptProperties();
const dataApiUrl = props.getProperty('DATA_API_URL') || 'https://icanhazdadjoke.com/';
const options = {
method: 'get',
headers: {
Accept: 'application/json'
},
muteHttpExceptions: true
};
const res = UrlFetchApp.fetch(dataApiUrl, options);
const code = res.getResponseCode();
const body = res.getContentText();
if (code < 200 || code >= 300) {
return {
source: 'error',
status: code,
body
};
}
try {
return JSON.parse(body);
} catch (e) {
return {
source: 'error',
status: code,
body,
parseError: String(e)
};
}
}
Then:
function testJoke() {
const data = fetchDataFromApi_();
Logger.log('Joke: ' + data.joke);
}
🔹 6. How This Fits Into the Hybrid AI Orchestrator
In your Hybrid AI Orchestrator project, the same fetchDataFromApi_() helper is used inside chatHybrid(question):
function chatHybrid(question) {
const q = (question || '').trim();
if (!q) throw new Error('Question is empty.');
// 1) Get data from API (this lesson)
const data = fetchDataFromApi_();
// 2) Ask local AI model to analyze it
const localAnalysis = callLocalAi_(q, data);
// 3) Ask Gemini to synthesize everything into a final answer
const finalAnswer = callGeminiOrchestrator_(q, data, localAnalysis);
return {
answer: finalAnswer,
raw: { data, localAnalysis }
};
}
So this lesson is the foundation:
First, we learn how to get JSON data into Apps Script. Then, we plug that data into local AI + Gemini.
🔹 7. Practice Tasks (Apps Script Exercises)
You can add these as end-of-lesson exercises in the blog:
🧪 Exercise 1 — Swap APIs Without Editing Code
- Set
DATA_API_URLto the cat facts API. - Run
testDataApiProperty()and log the fact. - Change
DATA_API_URLto the Bored API. - Run the same function — see how the data changes without touching code.
🧪 Exercise 2 — Build a Simple “Explain This” Function
function explainDataForAi_() {
const data = fetchDataFromApi_();
return JSON.stringify(data, null, 2);
}
Later, you’ll feed explainDataForAi_() into Gemini as context.
🧪 Exercise 3 — Add Basic Error Handling
Update fetchDataFromApi_() to throw an error if source === 'error', and handle that gracefully in chatHybrid().
