Code Examples
Complete, working examples for integrating the NutrientAPI nutrition analysis endpoint. Every example below includes error handling and response parsing.
API Endpoint:
Content-Type:
POST https://api.nutrientapi.com/v1/analyze
Authentication: Bearer token via the Authorization header.Content-Type:
application/json
Request Format
All examples below send the same request body:
{
"title": "Avocado Toast",
"ingredients": [
"2 slices whole wheat bread",
"1 medium avocado",
"1 tbsp lemon juice",
"1/4 tsp salt",
"pinch of red pepper flakes"
],
"servings": 2
}
Response Format
The API returns a JSON object with this structure:
{
"status": "success",
"ingredients": [
{
"parsed": "whole wheat bread",
"confidence": 0.95,
"nutrients": {
"calories": 160.4,
"protein": 7.8,
"fat": 2.4,
"carbs": 27.6,
// ... 10 more nutrients
}
}
// ... more ingredients
],
"totals": { /* sum of all ingredients */ },
"per_serving": { /* totals divided by servings */ },
"diet_labels": ["VEGAN", "VEGETARIAN"],
"health_labels": ["DAIRY_FREE", "EGG_FREE"]
}
curl
curl -X POST https://api.nutrientapi.com/v1/analyze \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"title": "Avocado Toast",
"ingredients": [
"2 slices whole wheat bread",
"1 medium avocado",
"1 tbsp lemon juice",
"1/4 tsp salt",
"pinch of red pepper flakes"
],
"servings": 2
}'
Python
Uses the requests library. Install with pip install requests.
import requests
import os
import sys
API_KEY = os.environ["NUTRIENTAPI_KEY"]
API_URL = "https://api.nutrientapi.com/v1/analyze"
def analyze_recipe(title, ingredients, servings=1):
"""Analyze a recipe and return nutrition data.
Args:
title: Recipe name (e.g. "Avocado Toast").
ingredients: List of ingredient strings in natural language.
servings: Number of servings the recipe makes.
Returns:
Parsed JSON response with nutrients, totals, and labels.
Raises:
requests.HTTPError: If the API returns a non-2xx status.
"""
response = requests.post(
API_URL,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}",
},
json={
"title": title,
"ingredients": ingredients,
"servings": servings,
},
timeout=30,
)
response.raise_for_status()
return response.json()
# --- Example usage ---
result = analyze_recipe(
title="Avocado Toast",
ingredients=[
"2 slices whole wheat bread",
"1 medium avocado",
"1 tbsp lemon juice",
"1/4 tsp salt",
"pinch of red pepper flakes",
],
servings=2,
)
# Print per-serving summary
per_serving = result["per_serving"]
print(f"Per serving: {per_serving['calories']:.0f} cal, "
f"{per_serving['protein']:.1f}g protein, "
f"{per_serving['fat']:.1f}g fat, "
f"{per_serving['carbs']:.1f}g carbs")
# Print labels
print(f"Diet labels: {', '.join(result['diet_labels'])}")
print(f"Health labels: {', '.join(result['health_labels'])}")
# Check confidence scores -- flag ingredients below threshold
for ing in result["ingredients"]:
if ing["confidence"] < 0.8:
print(f"Low confidence ({ing['confidence']:.2f}): {ing['parsed']}")
Error Handling (Python)
import requests
try:
result = analyze_recipe(
title="Avocado Toast",
ingredients=["2 slices whole wheat bread", "1 medium avocado"],
servings=2,
)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
print("Invalid API key. Check your NUTRIENTAPI_KEY.")
elif e.response.status_code == 422:
print(f"Validation error: {e.response.json()}")
elif e.response.status_code == 429:
print("Rate limited. Back off and retry.")
else:
print(f"API error {e.response.status_code}: {e.response.text}")
except requests.exceptions.Timeout:
print("Request timed out. Try again.")
except requests.exceptions.ConnectionError:
print("Could not connect to the API.")
JavaScript (Fetch API)
Works in browsers and modern JavaScript runtimes.
const API_KEY = "YOUR_API_KEY";
const API_URL = "https://api.nutrientapi.com/v1/analyze";
async function analyzeRecipe(title, ingredients, servings = 1) {
const response = await fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${API_KEY}`,
},
body: JSON.stringify({ title, ingredients, servings }),
});
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`API error ${response.status}: ${errorBody}`);
}
return response.json();
}
// --- Example usage ---
try {
const result = await analyzeRecipe(
"Avocado Toast",
[
"2 slices whole wheat bread",
"1 medium avocado",
"1 tbsp lemon juice",
"1/4 tsp salt",
"pinch of red pepper flakes",
],
2
);
// Per-serving summary
const ps = result.per_serving;
console.log(
`Per serving: ${Math.round(ps.calories)} cal, ` +
`${ps.protein.toFixed(1)}g protein, ` +
`${ps.fat.toFixed(1)}g fat, ` +
`${ps.carbs.toFixed(1)}g carbs`
);
// Labels
console.log("Diet labels:", result.diet_labels.join(", "));
console.log("Health labels:", result.health_labels.join(", "));
// Check for low-confidence ingredients
result.ingredients
.filter((ing) => ing.confidence < 0.8)
.forEach((ing) => {
console.warn(`Low confidence (${ing.confidence}): ${ing.parsed}`);
});
} catch (error) {
console.error("Failed to analyze recipe:", error.message);
}
Node.js
Uses the built-in fetch available in Node.js 18+. For older versions, install node-fetch.
const API_KEY = process.env.NUTRIENTAPI_KEY;
const API_URL = "https://api.nutrientapi.com/v1/analyze";
async function analyzeRecipe(title, ingredients, servings = 1) {
const response = await fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${API_KEY}`,
},
body: JSON.stringify({ title, ingredients, servings }),
});
if (!response.ok) {
const body = await response.text();
throw new Error(`NutrientAPI error ${response.status}: ${body}`);
}
return response.json();
}
// --- Example: Analyze and print a nutrition label ---
async function main() {
try {
const result = await analyzeRecipe(
"Avocado Toast",
[
"2 slices whole wheat bread",
"1 medium avocado",
"1 tbsp lemon juice",
"1/4 tsp salt",
"pinch of red pepper flakes",
],
2
);
// Print each ingredient with its confidence
console.log("Ingredients:");
for (const ing of result.ingredients) {
const cal = ing.nutrients.calories.toFixed(0);
console.log(` ${ing.parsed} - ${cal} cal (confidence: ${ing.confidence})`);
}
// Print per-serving totals
console.log("\nPer serving:");
const ps = result.per_serving;
console.log(` Calories: ${ps.calories.toFixed(0)}`);
console.log(` Protein: ${ps.protein.toFixed(1)}g`);
console.log(` Fat: ${ps.fat.toFixed(1)}g`);
console.log(` Carbs: ${ps.carbs.toFixed(1)}g`);
// Print labels
console.log(`\nDiet labels: ${result.diet_labels.join(", ")}`);
console.log(`Health labels: ${result.health_labels.join(", ")}`);
} catch (error) {
if (error.message.includes("401")) {
console.error("Invalid API key. Set NUTRIENTAPI_KEY environment variable.");
} else if (error.message.includes("429")) {
console.error("Rate limited. Implement exponential backoff.");
} else {
console.error("Error:", error.message);
}
process.exit(1);
}
}
main();
Ruby
Uses the standard library only (no gems required).
require "net/http"
require "json"
require "uri"
API_KEY = ENV.fetch("NUTRIENTAPI_KEY")
API_URL = URI("https://api.nutrientapi.com/v1/analyze")
def analyze_recipe(title:, ingredients:, servings: 1)
http = Net::HTTP.new(API_URL.host, API_URL.port)
http.use_ssl = true
http.read_timeout = 30
request = Net::HTTP::Post.new(API_URL.path)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer #{API_KEY}"
request.body = {
title: title,
ingredients: ingredients,
servings: servings
}.to_json
response = http.request(request)
case response
when Net::HTTPSuccess
JSON.parse(response.body)
when Net::HTTPUnauthorized
raise "Invalid API key. Check NUTRIENTAPI_KEY."
when Net::HTTPUnprocessableEntity
raise "Validation error: #{response.body}"
when Net::HTTPTooManyRequests
raise "Rate limited. Back off and retry."
else
raise "API error #{response.code}: #{response.body}"
end
end
# --- Example usage ---
result = analyze_recipe(
title: "Avocado Toast",
ingredients: [
"2 slices whole wheat bread",
"1 medium avocado",
"1 tbsp lemon juice",
"1/4 tsp salt",
"pinch of red pepper flakes"
],
servings: 2
)
# Per-serving summary
ps = result["per_serving"]
puts "Per serving: #{ps["calories"].round} cal, " \
"#{ps["protein"].round(1)}g protein, " \
"#{ps["fat"].round(1)}g fat, " \
"#{ps["carbs"].round(1)}g carbs"
# Labels
puts "Diet labels: #{result["diet_labels"].join(", ")}"
puts "Health labels: #{result["health_labels"].join(", ")}"
# Flag low-confidence matches
result["ingredients"].each do |ing|
if ing["confidence"] < 0.8
puts "Low confidence (#{ing["confidence"]}): #{ing["parsed"]}"
end
end
Integration Tips
Cache responses. Unlike some nutrition APIs, NutrientAPI allows you to cache results without restrictions. Store nutrition data alongside your recipes in your database. Only call the API when ingredients change.
Use confidence scores. Every ingredient in the response includes a
confidence field (0.0 to 1.0). Set a threshold for your app -- 0.8 is a good starting point. Flag or review results below your threshold rather than displaying them without qualification.
Handle rate limits. If you receive a
429 response, implement exponential backoff. Wait 1 second, then 2, then 4, up to a maximum. Do not retry immediately in a tight loop.
Common Patterns
- Batch analysis: Send all ingredients for a recipe in a single request rather than one ingredient at a time. The API is designed for whole-recipe analysis.
- Ingredient formatting: Include quantities and units in natural language.
"2 cups diced chicken breast"works better than"chicken breast"because the API can compute accurate gram weights from the quantity. - Servings: Set the
servingsfield to get automatic per-serving calculations in the response. You do not need to divide totals yourself. - Error responses: The API returns JSON error bodies with descriptive messages. Parse the response body on non-2xx status codes for actionable diagnostics.