Error Handling

The USDA FDC Python Client provides a comprehensive error handling system to help you handle various error conditions gracefully.

Exception Hierarchy

The library defines the following exception hierarchy:

  • FdcApiError: Base exception for all API errors - FdcAuthError: Authentication failed (invalid API key) - FdcRateLimitError: API rate limit exceeded - FdcValidationError: Invalid input parameters - FdcResourceNotFoundError: Requested resource not found

Basic Error Handling

Here’s how to handle errors when using the client:

from usda_fdc import FdcClient, FdcApiError, FdcAuthError, FdcRateLimitError

client = FdcClient(api_key="your_api_key_here")

try:
    food = client.get_food(1750340)
except FdcAuthError:
    print("Authentication failed. Check your API key.")
except FdcRateLimitError:
    print("Rate limit exceeded. Try again later.")
except FdcApiError as e:
    print(f"API error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

Handling Specific HTTP Status Codes

The FdcApiError exception includes the HTTP status code, which you can use for more specific error handling:

from usda_fdc import FdcClient, FdcApiError

client = FdcClient(api_key="your_api_key_here")

try:
    food = client.get_food(1750340)
except FdcApiError as e:
    if hasattr(e, 'status_code'):
        if e.status_code == 404:
            print("Food not found")
        elif e.status_code == 429:
            print("Too many requests. Try again later.")
        elif e.status_code >= 500:
            print("Server error. Try again later.")
        else:
            print(f"API error: {e}")
    else:
        print(f"API error without status code: {e}")

Retry Logic

For transient errors like rate limiting or server errors, you can implement retry logic:

import time
from usda_fdc import FdcClient, FdcApiError, FdcRateLimitError

client = FdcClient(api_key="your_api_key_here")

def get_food_with_retry(fdc_id, max_retries=3, retry_delay=5):
    retries = 0
    while retries < max_retries:
        try:
            return client.get_food(fdc_id)
        except FdcRateLimitError:
            retries += 1
            if retries < max_retries:
                print(f"Rate limit exceeded. Retrying in {retry_delay} seconds...")
                time.sleep(retry_delay)
                retry_delay *= 2  # Exponential backoff
            else:
                raise
        except FdcApiError as e:
            if hasattr(e, 'status_code') and e.status_code >= 500:
                retries += 1
                if retries < max_retries:
                    print(f"Server error. Retrying in {retry_delay} seconds...")
                    time.sleep(retry_delay)
                    retry_delay *= 2  # Exponential backoff
                else:
                    raise
            else:
                raise

# Use the retry function
try:
    food = get_food_with_retry(1750340)
except Exception as e:
    print(f"Failed after retries: {e}")

Logging Errors

It’s a good practice to log errors for debugging:

import logging
from usda_fdc import FdcClient, FdcApiError

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('usda_fdc')

client = FdcClient(api_key="your_api_key_here")

try:
    food = client.get_food(1750340)
except FdcApiError as e:
    logger.error(f"API error when getting food {1750340}: {e}", exc_info=True)
    # Handle the error appropriately
except Exception as e:
    logger.exception(f"Unexpected error when getting food {1750340}")
    # Handle the error appropriately