This is technically related to Gemini but wondering if anybody has any insight.
I signed up for a free version of Gemini so I could test out their API. I have created a key and it works perfectly in Postman when i do a raw JSON post with the url https://generativelanguage.googleapis.com/v1/models/gemini-2.0-flash:generateContent?key=MyKey
With the body
{
"contents": [
{
"parts": [
{
"text": "how big is the sun. Tell me in less than 20 characters"
}
]
}
]
}
However, I’ve tried a million and one ways or so it feels to try to get the same thing to work in Lucee, and it keeps kicking back a 404 error. Now the 404 is a bit misleading because I also posted the endpoint into a browser and got the 404 response because the body was missing, but it demonstrated that it gave a 404 even though the endpoint URL was correct.
Here’s one of the many attempts
<cfscript>
// API endpoint - DOUBLE CHECK THIS
apiUrl = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent";
// API key (IMPORTANT: Define this variable securely!)
apiKey = GEMINI_API_KEY;
// *** URL-encode the API key ***
apiKey = urlEncodedFormat(apiUrl);
cfhttp(url="#apiUrl#?key=#apiKey#", method="post", result="httpResponse") {
cfhttpparam type="header" name="Content-Type" value="application/json; charset=UTF-8"
cfhttpparam type="body" value='{"contents": [{"parts":[{"text": "test"}]}]}'
}
writeDump(httpResponse);
</cfscript>
here’s another
<cfscript>
// API endpoint from the working curl example
apiUrl = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent";
// API key (IMPORTANT: Define this variable securely!)
apiKey = GEMINI_API_KEY;
// Payload from the working curl example
payload = {
"contents": [
{
"parts": [
{
"text": "Tell me about the earth size in less than 30 characters" // Or "Write a story about a magic backpack."
}
]
}
]
};
// Serialize payload to JSON
payloadJson = serializeJSON(payload);
// *** Debugging: Ensure payloadJson is valid JSON ***
try {
deserializeJSON(payloadJson); // Try to deserialize it back
writeOutput("<br>Payload JSON is valid.<br>");
} catch (any e) {
writeOutput("<br>Payload JSON is NOT valid: #e.message#<br>");
// If it's invalid, inspect payloadJson closely!
}
// cfhttp to make the API call
cfhttp(url=apiUrl, method="post", result="httpResponse") {
// API key in the URL (as it works in your Postman example)
cfhttpparam(type="url", name="key", value="#apiKey#");
// Content-Type header (with charset) - EXACT MATCH TO POSTMAN
cfhttpparam(type="header", name="Content-Type", value="application/json; charset=UTF-8");
// Set the JSON payload as the body
cfhttpparam(type="body", value=payloadJson);
}
// *** Debugging: Output httpResponse ***
writeDump(httpResponse); // Inspect the entire httpResponse struct
// Process the API response
if (httpResponse.statusCode eq "200 OK") {
// Successful response
responseData = deserializeJSON(httpResponse.fileContent);
// *** Extract the answer - ADJUST THIS BASED ON ACTUAL RESPONSE STRUCTURE ***
// *** The structure of the response will vary depending on the Gemini model ***
if (structKeyExists(responseData, "candidates") && arrayLen(responseData.candidates) gt 0) {
// This is a likely path to the answer, but you *must* verify it
answer = responseData.candidates[1].content.parts[1].text;
// *** Gemini API does not provide token usage in the same way as OpenAI ***
tokensUsed = "N/A";
} else {
answer = "Error: No answer received from Gemini API";
tokensUsed = "N/A";
}
// Output the results
writeOutput("Question: Tell me about the earth size in less than 30 characters<br>");
writeOutput("Answer: #answer#<br>");
writeOutput("Tokens Used: #tokensUsed#");
} else {
// *** Handle errors from the Gemini API ***
writeOutput("Error: #httpResponse.status_code# - #httpResponse.status_text#<br>");
writeOutput("Response Content: #httpResponse.fileContent#");
// *** Log the error for debugging ***
// <cflog file="GeminiAPIError" text="Status: #httpResponse.statusCode#, #httpResponse.statusText#, Content: #httpResponse.fileContent#">
// *** Handle specific errors, such as rate limiting ***
if (httpResponse.status_code eq "429") {
writeOutput("<br>Rate limit exceeded. Please try again later.");
// Implement retry logic if needed (e.g., wait and try again)
}
}
</cfscript>
I’d use gemini and Deepseek to try and create these solutions (hence all the comments in there)
I’m hoping somebody else has come across this issue and might be able to help. Btw I’m running it locally on HTTP but I did also try it on HTTPS
Tech stack
- Lucee 6.1.1.118 (updating to 6.2.shortly)
- Java 11.0.21 (Eclipse Adoptium) 64bit
- Windows Server 2022 (10.0) 64bit
- IIS 10
21 posts - 3 participants