Tools
FoodFacts API - AI-Powered Nutrition & Recipe REST API
2025-12-15
0 views
admin
What I Built ## Architecture Diagram ## What Data Services Does FoodFacts API Provide? ## Key Features ## Who Is This API For? ## API Documentation ## Base URLs ## Authentication Strategy ## Rate Limiting ## API Endpoints ## /nutrition/ingredients ## /foods/search ## /nutrition/estimate ## /diet/plan ## /recipes/from-ingredients ## Using Public Endpoints ## Using Protected Endpoints ## The AI Prompt I Used ## AI-Generated Database Schema ## How I Refined the AI-Generated Code ## ⚙️ Challenge 1: Auto-Generated CRUD Endpoints ## ⚙️ Challenge 2: Schema Inconsistencies ## ⚙️ Challenge 3: API Rate Limiting ## ⚙️ Challenge 4: Exploring Xano Actions ## My Experience with Xano ## What Helped Most When Using Xano Xano AI-Powered Backend Challenge: Public API Submission This is a submission for the Xano AI-Powered Backend Challenge: Production-Ready Public API FoodFacts API is a production-ready public REST API that provides nutrition, meal, and food data powered by AI. It returns structured results that apps can rely on. Developers can use the API to analyze food, estimate calories and macronutrients, generate diet plans, and create recipes from natural language input. The API is stateless and built for real-world use in fitness apps, diet planners, recipe platforms, and health dashboards. FoodFacts API combines AI reasoning with strict JSON schemas to ensure responses stay predictable and easy to parse. FoodFacts API supports these services: All responses return clean, structured JSON designed for direct use in web and mobile apps. Food Nutrition Search
Developers can search nutrition data for common foods. This supports calorie tracking and food databases without extra setup. Meal and Ingredient Analysis
The API estimates nutrition from: This removes the need to maintain large food databases. AI-Generated Diet Plans
Based on user goals such as weight loss or muscle gain, the API generates multi-day plans that include: Recipe Generation
Given a list of ingredients, the API returns: Consistent JSON Responses
All endpoints enforce strict JSON schemas. The API avoids unstructured AI output so responses stay safe and predictable. FoodFacts API fits teams building: Authentication Group URL: FoodFacts API Group URL: FoodFacts API uses a hybrid authentication model: This approach keeps onboarding simple while protecting AI-heavy operations. To protect reliability and cost, we apply rate limiting to prevent abuse and stay within Gemini API limits (15 RPM for Flash). Purpose: Analyze ingredients and return total calories & macros Here we send a simple list of ingredients with quantities, and the API returns total calories, protein, carbs, and fats. Purpose: Search nutrition data for a food item This endpoint lets developers search for standardized nutrition data for a food item, normalized. Purpose: Estimate calories & macros from free-text Even when exact ingredients aren't known, developers can send a natural language description and get an estimated nutritional breakdown. Purpose: Generate a multi-day diet plan Authentication: Required Based on the user's goal and preferences, the API generates a complete multi-day diet plan. Purpose: Generate recipes from available ingredients Authentication: Required Developers can send a simple list of ingredients, and the API returns complete recipes with steps and nutrition. 2. Nutrition Estimate 3. Ingredient Analysis To use protected endpoints, you first need to create an AUTH Token using auth/signup & auth/login endpoints. Copy the "authToken" from the login response and use it in the following requests. 3. Diet Plan Generation The platform automatically created ~20 CRUD-style API endpoints based on the prompt. These endpoints followed a standard pattern: Instead of that, we manually designed and implemented the core APIs that actually power the product. For example, it created an endpoint called diet_plan, which looked like this: Good part 😄: Later we used the Logic Assistant to create multiple endpoints by describing the intent of each API in natural language. The assistant generated accurate function blocks such as input validation, conditional logic, external API requests, and response handling. The PROMPT we used with Logic Assistant looked like this: The output Logic Assistant generated was this: The above XanoScript had some issues: The prompt explicitly referenced the endpoint name nutrition/ingredients, but the logic assistant named it estimate_nutrition The output schema AI generated was (this was the biggest difference): However, it should have been the following, as stated in the prompt schema: The refined XanoScript we used: Similarly, we made improvements to other endpoints as well. One of the main challenges we faced was working within the API limits of Gemini 2.5 Flash. Since multiple endpoints depend on AI-generated responses, we had to be careful about how often requests were made and ensure that rate limiting was applied consistently. This required us to design our endpoints defensively, validate inputs early, and avoid unnecessary AI calls. Handling structured JSON responses reliably from the AI model also required iterative prompt refinement to keep outputs predictable for a production API. We also explored using Xano Actions to abstract shared logic such as validation and response normalization. While the concept is powerful, we found that integrating Actions into existing endpoints required careful understanding of how data flows between Actions and API stacks. Although Xano provides resources and videos around Actions, we realized that for this project, keeping the logic directly inside endpoints allowed us to move faster and maintain clarity. This exploration was still valuable, as it helped us better understand when Actions are most appropriate in real-world backends. The Logic Assistant was particularly valuable for rapidly prototyping endpoint logic. While it didn't always produce perfect code on the first try, it significantly reduced development time by generating a solid foundation that we could refine. The visual nature of Xano's function stack builder made it easy to understand data flow and debug issues. Combined with the built-in request debugger, we could quickly identify and fix problems in our API logic. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
https://x95f-42hw-risi.m2.xano.io/api:QC35j52Y Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
https://x95f-42hw-risi.m2.xano.io/api:QC35j52Y CODE_BLOCK:
https://x95f-42hw-risi.m2.xano.io/api:QC35j52Y CODE_BLOCK:
https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS CODE_BLOCK:
https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS CODE_BLOCK:
https://x95f-42hw-risi.m2.xano.io/api Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
https://x95f-42hw-risi.m2.xano.io/api CODE_BLOCK:
https://x95f-42hw-risi.m2.xano.io/api CODE_BLOCK:
redis.ratelimit { key = "recipes_fromingr_limit:" ~ $auth.id max = 15 ttl = 60 error = "Too many requests. Please try again in a minute."
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
redis.ratelimit { key = "recipes_fromingr_limit:" ~ $auth.id max = 15 ttl = 60 error = "Too many requests. Please try again in a minute."
} CODE_BLOCK:
redis.ratelimit { key = "recipes_fromingr_limit:" ~ $auth.id max = 15 ttl = 60 error = "Too many requests. Please try again in a minute."
} CODE_BLOCK:
{ "ingredients": [ "1 medium banana", "2 tbsp peanut butter" ]
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "ingredients": [ "1 medium banana", "2 tbsp peanut butter" ]
} CODE_BLOCK:
{ "ingredients": [ "1 medium banana", "2 tbsp peanut butter" ]
} CODE_BLOCK:
/foods/search?query=apple Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
/foods/search?query=apple CODE_BLOCK:
/foods/search?query=apple CODE_BLOCK:
{ "meal_description": "2 slices of pizza and a glass of coke"
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "meal_description": "2 slices of pizza and a glass of coke"
} CODE_BLOCK:
{ "meal_description": "2 slices of pizza and a glass of coke"
} CODE_BLOCK:
{ "goal": "weight loss", "days": 3, "diet_type": "vegetarian"
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "goal": "weight loss", "days": 3, "diet_type": "vegetarian"
} CODE_BLOCK:
{ "goal": "weight loss", "days": 3, "diet_type": "vegetarian"
} CODE_BLOCK:
{ "ingredients": ["chicken", "rice", "onion"]
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "ingredients": ["chicken", "rice", "onion"]
} CODE_BLOCK:
{ "ingredients": ["chicken", "rice", "onion"]
} COMMAND_BLOCK:
curl -X GET \ "https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/foods/search?query=banana" \ -H "Content-Type: application/json" Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X GET \ "https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/foods/search?query=banana" \ -H "Content-Type: application/json" COMMAND_BLOCK:
curl -X GET \ "https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/foods/search?query=banana" \ -H "Content-Type: application/json" COMMAND_BLOCK:
curl -X POST \ 'https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/nutrition/estimate' \ -H 'Content-Type: application/json' \ --data '{"meal_description":"Grilled chicken breast with brown rice and steamed broccoli"}' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST \ 'https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/nutrition/estimate' \ -H 'Content-Type: application/json' \ --data '{"meal_description":"Grilled chicken breast with brown rice and steamed broccoli"}' COMMAND_BLOCK:
curl -X POST \ 'https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/nutrition/estimate' \ -H 'Content-Type: application/json' \ --data '{"meal_description":"Grilled chicken breast with brown rice and steamed broccoli"}' COMMAND_BLOCK:
curl -X POST \ https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/nutrition/ingredients \ -H "Content-Type: application/json" \ -d '{ "ingredients": [ "1 medium banana", "2 tbsp peanut butter" ] }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST \ https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/nutrition/ingredients \ -H "Content-Type: application/json" \ -d '{ "ingredients": [ "1 medium banana", "2 tbsp peanut butter" ] }' COMMAND_BLOCK:
curl -X POST \ https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/nutrition/ingredients \ -H "Content-Type: application/json" \ -d '{ "ingredients": [ "1 medium banana", "2 tbsp peanut butter" ] }' COMMAND_BLOCK:
curl -X POST https://x95f-42hw-risi.m2.xano.io/api:QC35j52Y/auth/signup \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "name": "Test", "password": "testpassword" }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST https://x95f-42hw-risi.m2.xano.io/api:QC35j52Y/auth/signup \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "name": "Test", "password": "testpassword" }' COMMAND_BLOCK:
curl -X POST https://x95f-42hw-risi.m2.xano.io/api:QC35j52Y/auth/signup \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "name": "Test", "password": "testpassword" }' COMMAND_BLOCK:
curl -X POST https://x95f-42hw-risi.m2.xano.io/api:QC35j52Y/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "password": "testpassword" }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST https://x95f-42hw-risi.m2.xano.io/api:QC35j52Y/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "password": "testpassword" }' COMMAND_BLOCK:
curl -X POST https://x95f-42hw-risi.m2.xano.io/api:QC35j52Y/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "password": "testpassword" }' COMMAND_BLOCK:
curl -X POST \ https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/diet/plan \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "goal": "weight_loss", "days": 30 }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST \ https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/diet/plan \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "goal": "weight_loss", "days": 30 }' COMMAND_BLOCK:
curl -X POST \ https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/diet/plan \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "goal": "weight_loss", "days": 30 }' COMMAND_BLOCK:
curl -X POST \ https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/recipes/from-ingredients \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "ingredients": [ "tomato", "cheese", "bread" ] }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST \ https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/recipes/from-ingredients \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "ingredients": [ "tomato", "cheese", "bread" ] }' COMMAND_BLOCK:
curl -X POST \ https://x95f-42hw-risi.m2.xano.io/api:GZXOANAS/recipes/from-ingredients \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "ingredients": [ "tomato", "cheese", "bread" ] }' CODE_BLOCK:
Build a production-ready public REST API called "FoodFacts API". This is a backend-only service (no UI) designed for third-party developers
building fitness, health, diet, and food applications. The API must return structured JSON only and be ready for real-world usage. Core features and endpoints: 1. POST /nutrition/ingredients Input: { ingredients: [string] } Behavior:
- Accept a list of ingredients such as "2 eggs", "1 cup milk"
- Use AI to estimate nutrition
- Return total calories, protein, carbs, fats
- Include a per-ingredient breakdown 2. GET /foods/search?query= Behavior:
- Search a food item by name
- Return nutrition facts per serving and per 100g
- Include category and portion information 3. POST /nutrition/estimate Input: { meal_description: string } Behavior:
- Accept a natural language meal description
- Estimate total calories, protein, carbs, and fats 4. POST /diet/plan Input: { goal: string, days: number } Behavior:
- Generate a day-wise AI-powered diet plan
- Include meals per day
- Include daily calorie targets
- Provide a grocery list and health tips 5. POST /recipes/from-ingredients Input: { ingredients: [string] } Behavior:
- Generate 3–5 recipes using the provided ingredients
- Include steps and estimated nutrition for each recipe Technical requirements:
- Use API-first design
- Structured JSON responses only
- Clear request and response schemas
- Error handling for invalid input
- Ready for API key authentication and rate limiting
- No frontend or UI logic This API should demonstrate best practices for a consumable public API
built with Xano and AI-powered external requests. Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
Build a production-ready public REST API called "FoodFacts API". This is a backend-only service (no UI) designed for third-party developers
building fitness, health, diet, and food applications. The API must return structured JSON only and be ready for real-world usage. Core features and endpoints: 1. POST /nutrition/ingredients Input: { ingredients: [string] } Behavior:
- Accept a list of ingredients such as "2 eggs", "1 cup milk"
- Use AI to estimate nutrition
- Return total calories, protein, carbs, fats
- Include a per-ingredient breakdown 2. GET /foods/search?query= Behavior:
- Search a food item by name
- Return nutrition facts per serving and per 100g
- Include category and portion information 3. POST /nutrition/estimate Input: { meal_description: string } Behavior:
- Accept a natural language meal description
- Estimate total calories, protein, carbs, and fats 4. POST /diet/plan Input: { goal: string, days: number } Behavior:
- Generate a day-wise AI-powered diet plan
- Include meals per day
- Include daily calorie targets
- Provide a grocery list and health tips 5. POST /recipes/from-ingredients Input: { ingredients: [string] } Behavior:
- Generate 3–5 recipes using the provided ingredients
- Include steps and estimated nutrition for each recipe Technical requirements:
- Use API-first design
- Structured JSON responses only
- Clear request and response schemas
- Error handling for invalid input
- Ready for API key authentication and rate limiting
- No frontend or UI logic This API should demonstrate best practices for a consumable public API
built with Xano and AI-powered external requests. CODE_BLOCK:
Build a production-ready public REST API called "FoodFacts API". This is a backend-only service (no UI) designed for third-party developers
building fitness, health, diet, and food applications. The API must return structured JSON only and be ready for real-world usage. Core features and endpoints: 1. POST /nutrition/ingredients Input: { ingredients: [string] } Behavior:
- Accept a list of ingredients such as "2 eggs", "1 cup milk"
- Use AI to estimate nutrition
- Return total calories, protein, carbs, fats
- Include a per-ingredient breakdown 2. GET /foods/search?query= Behavior:
- Search a food item by name
- Return nutrition facts per serving and per 100g
- Include category and portion information 3. POST /nutrition/estimate Input: { meal_description: string } Behavior:
- Accept a natural language meal description
- Estimate total calories, protein, carbs, and fats 4. POST /diet/plan Input: { goal: string, days: number } Behavior:
- Generate a day-wise AI-powered diet plan
- Include meals per day
- Include daily calorie targets
- Provide a grocery list and health tips 5. POST /recipes/from-ingredients Input: { ingredients: [string] } Behavior:
- Generate 3–5 recipes using the provided ingredients
- Include steps and estimated nutrition for each recipe Technical requirements:
- Use API-first design
- Structured JSON responses only
- Clear request and response schemas
- Error handling for invalid input
- Ready for API key authentication and rate limiting
- No frontend or UI logic This API should demonstrate best practices for a consumable public API
built with Xano and AI-powered external requests. CODE_BLOCK:
// Query all diet_plan records
query diet_plan verb=GET { api_group = "FoodFacts API Group" input { } stack { db.query diet_plan { return = {type: "list"} } as $diet_plan } response = $diet_plan
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// Query all diet_plan records
query diet_plan verb=GET { api_group = "FoodFacts API Group" input { } stack { db.query diet_plan { return = {type: "list"} } as $diet_plan } response = $diet_plan
} CODE_BLOCK:
// Query all diet_plan records
query diet_plan verb=GET { api_group = "FoodFacts API Group" input { } stack { db.query diet_plan { return = {type: "list"} } as $diet_plan } response = $diet_plan
} CODE_BLOCK:
You are building logic for a public API endpoint: POST /nutrition/ingredients. Goal:
Analyze a list of food ingredients and return estimated nutrition using AI. Input:
- ingredients: array of strings (required)
Example: ["2 eggs", "1 cup milk", "1 banana"] Logic requirements:
1. Validate input:
- ingredients must be an array
- array must not be empty
- return a clear JSON error if invalid 2. Build an AI prompt that asks the model to:
- Estimate calories, protein, carbs, and fats for each ingredient
- Calculate total calories, protein, carbs, and fats
- Return JSON only (no explanations, no markdown) Expected AI response format:
{ "total_calories": number, "total_protein": number, "total_carbs": number, "total_fats": number, "breakdown": [ { "item": string, "calories": number, "protein": number, "carbs": number, "fats": number } ]
} 3. Use an external API request to call an AI model (Google Gemini 1.5 Flash or equivalent) to generate nutrition estimates. 4. Parse and validate the AI JSON response.
- If parsing fails, return a graceful error message. 5. Return a clean JSON response with:
- total calories
- total protein
- total carbs
- total fats
- per-ingredient breakdown Additional constraints:
- No database writes required
- Stateless request
- JSON responses only
- Production-ready error handling
- Optimized for a public, API-key protected endpoint Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
You are building logic for a public API endpoint: POST /nutrition/ingredients. Goal:
Analyze a list of food ingredients and return estimated nutrition using AI. Input:
- ingredients: array of strings (required)
Example: ["2 eggs", "1 cup milk", "1 banana"] Logic requirements:
1. Validate input:
- ingredients must be an array
- array must not be empty
- return a clear JSON error if invalid 2. Build an AI prompt that asks the model to:
- Estimate calories, protein, carbs, and fats for each ingredient
- Calculate total calories, protein, carbs, and fats
- Return JSON only (no explanations, no markdown) Expected AI response format:
{ "total_calories": number, "total_protein": number, "total_carbs": number, "total_fats": number, "breakdown": [ { "item": string, "calories": number, "protein": number, "carbs": number, "fats": number } ]
} 3. Use an external API request to call an AI model (Google Gemini 1.5 Flash or equivalent) to generate nutrition estimates. 4. Parse and validate the AI JSON response.
- If parsing fails, return a graceful error message. 5. Return a clean JSON response with:
- total calories
- total protein
- total carbs
- total fats
- per-ingredient breakdown Additional constraints:
- No database writes required
- Stateless request
- JSON responses only
- Production-ready error handling
- Optimized for a public, API-key protected endpoint CODE_BLOCK:
You are building logic for a public API endpoint: POST /nutrition/ingredients. Goal:
Analyze a list of food ingredients and return estimated nutrition using AI. Input:
- ingredients: array of strings (required)
Example: ["2 eggs", "1 cup milk", "1 banana"] Logic requirements:
1. Validate input:
- ingredients must be an array
- array must not be empty
- return a clear JSON error if invalid 2. Build an AI prompt that asks the model to:
- Estimate calories, protein, carbs, and fats for each ingredient
- Calculate total calories, protein, carbs, and fats
- Return JSON only (no explanations, no markdown) Expected AI response format:
{ "total_calories": number, "total_protein": number, "total_carbs": number, "total_fats": number, "breakdown": [ { "item": string, "calories": number, "protein": number, "carbs": number, "fats": number } ]
} 3. Use an external API request to call an AI model (Google Gemini 1.5 Flash or equivalent) to generate nutrition estimates. 4. Parse and validate the AI JSON response.
- If parsing fails, return a graceful error message. 5. Return a clean JSON response with:
- total calories
- total protein
- total carbs
- total fats
- per-ingredient breakdown Additional constraints:
- No database writes required
- Stateless request
- JSON responses only
- Production-ready error handling
- Optimized for a public, API-key protected endpoint COMMAND_BLOCK:
// Estimates nutrition facts for a list of ingredients using AI.
query estimate_nutrition verb=POST { api_group = "FoodFacts API Group" input { // List of ingredients to analyze (e.g., "1 cup rice", "100g chicken") text[] ingredients } stack { // Validate that the ingredients array is not empty precondition (($input.ingredients | count) > 0) { error_type = "inputerror" error = "Ingredients list cannot be empty." } // Construct the AI prompt var $prompt { value = "Estimate the nutrition facts for these ingredients: " ~ ($input.ingredients | join: ", ") ~ ". Return strictly a JSON object with keys: " ~ "total_calories (int), total_protein_g (decimal), " ~ "total_carbs_g (decimal), total_fats_g (decimal), " ~ "and ingredients (array of objects with name, calories, " ~ "protein_g, carbs_g, fats_g). " ~ "Do not use markdown formatting." } // Call Google Gemini API api.request { url = "https://generativelanguage.googleapis.com/v1beta/models/" ~ "gemini-2.5-flash:generateContent?key=" ~ $env.GEMINI_API_KEY method = "POST" params = { contents: [ { parts: [ { text: $prompt } ] } ] } headers = [] | push: "Content-Type: application/json" } as $ai_response // Parse the response try_catch { try { var $raw_content { value = $ai_response.response.result.candidates[0] .content.parts[0].text } // Clean potential markdown formatting just in case var $clean_content { value = $raw_content | replace: "``` json", "" | replace: " ```", "" | trim } var $nutrition_data { value = $clean_content | json_decode } } catch { throw { name: "inputerror" value = "Unable to process nutrition data from AI response." } } } } response = $nutrition_data
} Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// Estimates nutrition facts for a list of ingredients using AI.
query estimate_nutrition verb=POST { api_group = "FoodFacts API Group" input { // List of ingredients to analyze (e.g., "1 cup rice", "100g chicken") text[] ingredients } stack { // Validate that the ingredients array is not empty precondition (($input.ingredients | count) > 0) { error_type = "inputerror" error = "Ingredients list cannot be empty." } // Construct the AI prompt var $prompt { value = "Estimate the nutrition facts for these ingredients: " ~ ($input.ingredients | join: ", ") ~ ". Return strictly a JSON object with keys: " ~ "total_calories (int), total_protein_g (decimal), " ~ "total_carbs_g (decimal), total_fats_g (decimal), " ~ "and ingredients (array of objects with name, calories, " ~ "protein_g, carbs_g, fats_g). " ~ "Do not use markdown formatting." } // Call Google Gemini API api.request { url = "https://generativelanguage.googleapis.com/v1beta/models/" ~ "gemini-2.5-flash:generateContent?key=" ~ $env.GEMINI_API_KEY method = "POST" params = { contents: [ { parts: [ { text: $prompt } ] } ] } headers = [] | push: "Content-Type: application/json" } as $ai_response // Parse the response try_catch { try { var $raw_content { value = $ai_response.response.result.candidates[0] .content.parts[0].text } // Clean potential markdown formatting just in case var $clean_content { value = $raw_content | replace: "``` json", "" | replace: " ```", "" | trim } var $nutrition_data { value = $clean_content | json_decode } } catch { throw { name: "inputerror" value = "Unable to process nutrition data from AI response." } } } } response = $nutrition_data
} COMMAND_BLOCK:
// Estimates nutrition facts for a list of ingredients using AI.
query estimate_nutrition verb=POST { api_group = "FoodFacts API Group" input { // List of ingredients to analyze (e.g., "1 cup rice", "100g chicken") text[] ingredients } stack { // Validate that the ingredients array is not empty precondition (($input.ingredients | count) > 0) { error_type = "inputerror" error = "Ingredients list cannot be empty." } // Construct the AI prompt var $prompt { value = "Estimate the nutrition facts for these ingredients: " ~ ($input.ingredients | join: ", ") ~ ". Return strictly a JSON object with keys: " ~ "total_calories (int), total_protein_g (decimal), " ~ "total_carbs_g (decimal), total_fats_g (decimal), " ~ "and ingredients (array of objects with name, calories, " ~ "protein_g, carbs_g, fats_g). " ~ "Do not use markdown formatting." } // Call Google Gemini API api.request { url = "https://generativelanguage.googleapis.com/v1beta/models/" ~ "gemini-2.5-flash:generateContent?key=" ~ $env.GEMINI_API_KEY method = "POST" params = { contents: [ { parts: [ { text: $prompt } ] } ] } headers = [] | push: "Content-Type: application/json" } as $ai_response // Parse the response try_catch { try { var $raw_content { value = $ai_response.response.result.candidates[0] .content.parts[0].text } // Clean potential markdown formatting just in case var $clean_content { value = $raw_content | replace: "``` json", "" | replace: " ```", "" | trim } var $nutrition_data { value = $clean_content | json_decode } } catch { throw { name: "inputerror" value = "Unable to process nutrition data from AI response." } } } } response = $nutrition_data
} CODE_BLOCK:
total_calories (int)
total_protein_g (decimal)
total_carbs_g (decimal)
total_fats_g (decimal)
ingredients: [ { name, calories, protein_g, carbs_g, fats_g }
] Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
total_calories (int)
total_protein_g (decimal)
total_carbs_g (decimal)
total_fats_g (decimal)
ingredients: [ { name, calories, protein_g, carbs_g, fats_g }
] CODE_BLOCK:
total_calories (int)
total_protein_g (decimal)
total_carbs_g (decimal)
total_fats_g (decimal)
ingredients: [ { name, calories, protein_g, carbs_g, fats_g }
] CODE_BLOCK:
total_calories (number)
total_protein (number)
total_carbs (number)
total_fats (number)
breakdown: [ { item, calories, protein, carbs, fats }
] Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
total_calories (number)
total_protein (number)
total_carbs (number)
total_fats (number)
breakdown: [ { item, calories, protein, carbs, fats }
] CODE_BLOCK:
total_calories (number)
total_protein (number)
total_carbs (number)
total_fats (number)
breakdown: [ { item, calories, protein, carbs, fats }
] COMMAND_BLOCK:
// Estimates nutritional information for a list of ingredients using AI.
query "nutrition/ingredients" verb=POST { api_group = "FoodFacts API Group" input { // List of ingredients to analyze (e.g., ["1 cup rice", "100g chicken"]) text[] ingredients } stack { // Validate that the input array is not empty precondition (($input.ingredients | count) > 0) { error_type = "inputerror" error = "The ingredients list cannot be empty." } // Construct the prompt for the AI model var $prompt { value = "Analyze the following ingredients: " ~ ($input.ingredients | join: ", ") ~ ". Provide a nutritional estimation. " ~ "Return ONLY a raw JSON object (no markdown formatting, no code blocks) " ~ "adhering strictly to this schema: " ~ "{ \"total_calories\": number, " ~ "\"total_protein\": number, " ~ "\"total_carbs\": number, " ~ "\"total_fats\": number, " ~ "\"breakdown\": [ " ~ "{ \"item\": string, \"calories\": number, " ~ "\"protein\": number, \"carbs\": number, \"fats\": number } " ~ "] }. " ~ "Ensure all numeric values are returned as numbers, not strings." } // Call Google Gemini 2.5 Flash API api.request { url = "https://generativelanguage.googleapis.com/v1beta/models/" ~ "gemini-2.5-flash:generateContent?key=" ~ $env.GEMINI_API_KEY method = "POST" params = { contents: [ { parts: [ { text: $prompt } ] } ] } headers = [] | push: "Content-Type: application/json" } as $gemini_response // Extract the raw text from the response var $raw_content { value = $gemini_response.response.result .candidates[0].content.parts[0].text } // Clean the response text by removing markdown artifacts if present var $cleaned_content { value = $raw_content | replace: "``` json", "" | replace: " ```", "" | trim } // Attempt to parse the cleaned text into a JSON object try_catch { try { var $nutrition_data { value = $cleaned_content | json_decode } } catch { throw { name = "ParsingError" value = "Failed to parse AI response into valid JSON. Raw response: " ~ $cleaned_content } } } } response = $nutrition_data
} Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// Estimates nutritional information for a list of ingredients using AI.
query "nutrition/ingredients" verb=POST { api_group = "FoodFacts API Group" input { // List of ingredients to analyze (e.g., ["1 cup rice", "100g chicken"]) text[] ingredients } stack { // Validate that the input array is not empty precondition (($input.ingredients | count) > 0) { error_type = "inputerror" error = "The ingredients list cannot be empty." } // Construct the prompt for the AI model var $prompt { value = "Analyze the following ingredients: " ~ ($input.ingredients | join: ", ") ~ ". Provide a nutritional estimation. " ~ "Return ONLY a raw JSON object (no markdown formatting, no code blocks) " ~ "adhering strictly to this schema: " ~ "{ \"total_calories\": number, " ~ "\"total_protein\": number, " ~ "\"total_carbs\": number, " ~ "\"total_fats\": number, " ~ "\"breakdown\": [ " ~ "{ \"item\": string, \"calories\": number, " ~ "\"protein\": number, \"carbs\": number, \"fats\": number } " ~ "] }. " ~ "Ensure all numeric values are returned as numbers, not strings." } // Call Google Gemini 2.5 Flash API api.request { url = "https://generativelanguage.googleapis.com/v1beta/models/" ~ "gemini-2.5-flash:generateContent?key=" ~ $env.GEMINI_API_KEY method = "POST" params = { contents: [ { parts: [ { text: $prompt } ] } ] } headers = [] | push: "Content-Type: application/json" } as $gemini_response // Extract the raw text from the response var $raw_content { value = $gemini_response.response.result .candidates[0].content.parts[0].text } // Clean the response text by removing markdown artifacts if present var $cleaned_content { value = $raw_content | replace: "``` json", "" | replace: " ```", "" | trim } // Attempt to parse the cleaned text into a JSON object try_catch { try { var $nutrition_data { value = $cleaned_content | json_decode } } catch { throw { name = "ParsingError" value = "Failed to parse AI response into valid JSON. Raw response: " ~ $cleaned_content } } } } response = $nutrition_data
} COMMAND_BLOCK:
// Estimates nutritional information for a list of ingredients using AI.
query "nutrition/ingredients" verb=POST { api_group = "FoodFacts API Group" input { // List of ingredients to analyze (e.g., ["1 cup rice", "100g chicken"]) text[] ingredients } stack { // Validate that the input array is not empty precondition (($input.ingredients | count) > 0) { error_type = "inputerror" error = "The ingredients list cannot be empty." } // Construct the prompt for the AI model var $prompt { value = "Analyze the following ingredients: " ~ ($input.ingredients | join: ", ") ~ ". Provide a nutritional estimation. " ~ "Return ONLY a raw JSON object (no markdown formatting, no code blocks) " ~ "adhering strictly to this schema: " ~ "{ \"total_calories\": number, " ~ "\"total_protein\": number, " ~ "\"total_carbs\": number, " ~ "\"total_fats\": number, " ~ "\"breakdown\": [ " ~ "{ \"item\": string, \"calories\": number, " ~ "\"protein\": number, \"carbs\": number, \"fats\": number } " ~ "] }. " ~ "Ensure all numeric values are returned as numbers, not strings." } // Call Google Gemini 2.5 Flash API api.request { url = "https://generativelanguage.googleapis.com/v1beta/models/" ~ "gemini-2.5-flash:generateContent?key=" ~ $env.GEMINI_API_KEY method = "POST" params = { contents: [ { parts: [ { text: $prompt } ] } ] } headers = [] | push: "Content-Type: application/json" } as $gemini_response // Extract the raw text from the response var $raw_content { value = $gemini_response.response.result .candidates[0].content.parts[0].text } // Clean the response text by removing markdown artifacts if present var $cleaned_content { value = $raw_content | replace: "``` json", "" | replace: " ```", "" | trim } // Attempt to parse the cleaned text into a JSON object try_catch { try { var $nutrition_data { value = $cleaned_content | json_decode } } catch { throw { name = "ParsingError" value = "Failed to parse AI response into valid JSON. Raw response: " ~ $cleaned_content } } } } response = $nutrition_data
} - Food nutrition data such as calories, protein, carbs, and fats
- Meal-level macro estimates from free-text descriptions
- Ingredient-based nutrition analysis
- Goal-based diet plan generation
- Recipe generation from available ingredients - A list of ingredients
- A natural language meal description - Daily meals
- Estimated calories
- Grocery lists
- Health tips - Recipe ideas
- Preparation steps
- Estimated nutrition - Fitness and calorie-tracking apps
- Diet and wellness platforms
- Recipe and meal-planning tools
- Health-focused SaaS products
- AI-powered food features - Public endpoints allow anonymous access for testing and basic use. These include: foods/search, nutrition/estimate & nutrition/ingredients
- Protected endpoints require Bearer tokens. These include: diet/plan, recipes/from-ingredients - One or two function blocks per endpoint
- Basic create/read/update/delete logic
- No business rules, validations, or AI orchestration - The prompt explicitly referenced the endpoint name nutrition/ingredients, but the logic assistant named it estimate_nutrition
- The output schema AI generated was (this was the biggest difference): - Visual logic builder for clear and debuggable flows
- Built-in debugger for inspecting live requests and responses
- Simple external API integration with secure key storage
- Built-in authentication and rate limiting
- Structured error handling
- Fast iteration from idea to stable API - dev.to/mohitb_twt - [email protected]
- dev.to/deebi9 - [email protected]
how-totutorialguidedev.toaicrondatabase