Advanced Usage

This guide covers advanced usage patterns for the USDA FDC Python Client.

Custom API Requests

For more control over API requests, you can use the low-level _make_request method:

from usda_fdc import FdcClient

client = FdcClient(api_key="your_api_key_here")

# Make a custom request
data = client._make_request(
    endpoint="foods/search",
    params={
        "query": "apple",
        "pageSize": 25,
        "pageNumber": 1,
        "sortBy": "dataType.keyword",
        "sortOrder": "asc"
    }
)

Unit Conversion

The library provides utilities for converting between different measurement units:

from usda_fdc.utils import convert_measurement, parse_unit_and_value

# Convert between units
grams = convert_measurement(1, "cup", "g")
print(f"1 cup = {grams} grams")

# Parse a measurement string
amount, unit = parse_unit_and_value("2.5 tbsp")
print(f"Amount: {amount}, Unit: {unit}")

# Convert to grams
from usda_fdc.utils import convert_to_grams

grams = convert_to_grams(1, "oz")
print(f"1 oz = {grams} grams")

Batch Processing

For processing large numbers of food items, use batch operations:

from usda_fdc import FdcClient
import time

client = FdcClient(api_key="your_api_key_here")

# Get all food IDs (this could be a large number)
all_ids = []
page = 1
while True:
    foods = client.list_foods(page_size=200, page_number=page)
    if not foods:
        break
    all_ids.extend([food.fdc_id for food in foods])
    page += 1
    time.sleep(1)  # Be nice to the API

print(f"Found {len(all_ids)} food IDs")

# Process in batches of 20 (API limit)
batch_size = 20
for i in range(0, len(all_ids), batch_size):
    batch = all_ids[i:i+batch_size]
    foods = client.get_foods(batch)
    print(f"Processed batch {i//batch_size + 1}/{(len(all_ids) + batch_size - 1)//batch_size}")
    time.sleep(1)  # Be nice to the API

Custom Data Processing

You can extend the library’s data models for custom processing:

from usda_fdc import FdcClient
from usda_fdc.models import Food

class EnhancedFood(Food):
    def calculate_calories_per_gram(self):
        for nutrient in self.nutrients:
            if nutrient.name == "Energy" and nutrient.unit_name == "kcal":
                return nutrient.amount / 100  # per gram
        return 0

    def calculate_protein_percentage(self):
        energy = 0
        protein_energy = 0

        for nutrient in self.nutrients:
            if nutrient.name == "Energy" and nutrient.unit_name == "kcal":
                energy = nutrient.amount
            elif nutrient.name == "Protein" and nutrient.unit_name == "g":
                # Protein has 4 calories per gram
                protein_energy = nutrient.amount * 4

        if energy > 0:
            return (protein_energy / energy) * 100
        return 0

# Use the enhanced class
client = FdcClient(api_key="your_api_key_here")
food_data = client.get_food(1750340)

# Convert to enhanced food
enhanced_food = EnhancedFood(
    fdc_id=food_data.fdc_id,
    description=food_data.description,
    data_type=food_data.data_type,
    nutrients=food_data.nutrients,
    food_portions=food_data.food_portions
)

print(f"Calories per gram: {enhanced_food.calculate_calories_per_gram()}")
print(f"Protein percentage: {enhanced_food.calculate_protein_percentage()}%")

Rate Limiting

To avoid hitting API rate limits, implement a simple rate limiter:

import time
from usda_fdc import FdcClient

class RateLimitedClient(FdcClient):
    def __init__(self, api_key, requests_per_minute=10, **kwargs):
        super().__init__(api_key, **kwargs)
        self.requests_per_minute = requests_per_minute
        self.interval = 60 / requests_per_minute
        self.last_request_time = 0

    def _make_request(self, endpoint, method="GET", params=None, data=None):
        # Wait if needed
        current_time = time.time()
        time_since_last = current_time - self.last_request_time

        if time_since_last < self.interval:
            time.sleep(self.interval - time_since_last)

        # Make the request
        result = super()._make_request(endpoint, method, params, data)

        # Update last request time
        self.last_request_time = time.time()

        return result

# Use the rate-limited client
client = RateLimitedClient(
    api_key="your_api_key_here",
    requests_per_minute=5  # Maximum 5 requests per minute
)