Skip to content

REST API ​

API versions ​

The REST API is served under /api/v2. The previous /api/v1 API was deprecated with the 2.0.0 release and removed in 2.4.0; there is no compatibility layer left. If you still call /api/v1, switch the base path to /api/v2 and note the two endpoints that also changed location:

  • /api/v1/fddbdata/migrateToInfluxDb → /api/v2/migration/toInfluxDb
  • /api/v1/fddbdata/stats and /stats/averages → /api/v2/stats and /api/v2/stats/averages

Overview ​

This API allows you to retrieve and export data from the database. The endpoints support operations such as retrieving all data, filtering by date, searching for specific products, and exporting data for a specified date range.

Interactive API reference ​

Your own instance serves an always-current specification, generated from the running code:

/swagger-ui.htmlSwagger UI, with "try it out" enabled against your own data
/api-docsThe OpenAPI document itself, as JSON

That generated document is the authoritative one — it cannot disagree with the code it was produced from. A snapshot is also committed to this repository for reading without a running instance: fddb-exporter-api-v2.yaml. It is regenerated by hand, so if the two ever disagree, believe /api-docs.

Both paths are unauthenticated, like the rest of the application, and Swagger UI's "try it out" executes

real requests — including exports. Do not expose them publicly; see Securing your instance.

Example responses:

  1. example response for querying data from the database
  2. example response when querying a product name
  3. example response when retrieving stats

Error responses 2.5.0+ ​

Errors handled by the global exception handler use RFC 7807 problem details, served as application/problem+json. One parser handles all of them — there is no per-endpoint or per-error key to learn.

json
{
  "type": "https://github.com/itobey/fddb-exporter/problems/invalid-date-range",
  "title": "Invalid Date Range",
  "status": 400,
  "detail": "The 'from' date cannot be after the 'to' date",
  "instance": "/api/v2/fddbdata/range"
}

detail is the sentence to show a user. Bean-validation failures add one extra member, errors, mapping each rejected field to its message:

json
{
  "title": "Validation Failed",
  "status": 400,
  "detail": "One or more fields of the request are invalid",
  "errors": {
    "fromDate": "From date must be in the format YYYY-MM-DD",
    "toDate": "To date cannot be null"
  }
}

The same mistake always produces the same status, whichever endpoint detects it:

StatusMeaning
400 Bad RequestAnything the caller can fix: an inverted or oversized date range, a malformed date, a rejected parameter, or a range with no entries to average
404 Not FoundThe requested day has no data, or the diary page could not be parsed into any
409 ConflictAnother export is already running - see only one export at a time
413 Payload Too LargeA download would exceed the 365-day limit
502 Bad GatewayLogging in to fddb.info failed - the upstream site rejected the configured credentials
503 Service UnavailableThe endpoint needs a store that is not configured on this instance
500 Internal Server ErrorAn unexpected failure. The body is deliberately generic; the stack trace is in the server log

Before 2.5.0 the body was an ad-hoc object with a different key per error (dateTimeError,

exportError, authenticationError), validation messages sat at the root of the object rather than under errors, and some endpoints answered with a bare string. Failed logins were 500 and unconfigured stores were 500.

Endpoints ​

Retrieve All Data ​

GET /api/v2/fddbdata

  • Description: Retrieves all data from the database as JSON.

  • Response: A JSON array containing all entries (see full example response of an entry in this array).

    json
    [
        {
          "id": "66d18658bc73187ea859f67c",
          "date": "2024-08-28",
          "products": [
            {
              "name": "Panini Rolls",
              "amount": "75 g",
              "calories": 176.0,
              "fat": 2.2,
              "carbs": 33.8,
              "protein": 2.8,
              "link": "/db/en/food/schaer_panini_rolls/index.html"
            },
            [...]
          ],
          "totalCalories": 2437.0,
          "totalFat": 93.5,
          "totalCarbs": 285.5,
          "totalSugar": 76.3,
          "totalProtein": 103.9,
          "totalFibre": 10.3
        },
      [...]
    ]

Retrieve Data by Date ​

GET /api/v2/fddbdata/{date}

  • Description: Retrieves data for a specific day from the database as JSON.

  • Path Parameter:

    • date (required): The specific date in YYYY-MM-DD format.
  • Example: /api/v2/fddbdata/2024-08-24

  • Response: A JSON object containing the data for the specified date (see full example response).

    json
    {
      "id": "66d18658bc73187ea859f67c",
      "date": "2024-08-28",
      "products": [
        {
          "name": "Panini Rolls",
          "amount": "75 g",
          "calories": 176.0,
          "fat": 2.2,
          "carbs": 33.8,
          "protein": 2.8,
          "link": "/db/en/food/schaer_panini_rolls/index.html"
        },
        [...]
      ],
      "totalCalories": 2437.0,
      "totalFat": 93.5,
      "totalCarbs": 285.5,
      "totalSugar": 76.3,
      "totalProtein": 103.9,
      "totalFibre": 10.3
    }

Retrieve Data by Date Range 2.3.0+ ​

GET /api/v2/fddbdata/range?fromDate={startDate}&toDate={endDate}&includeProducts={bool}

  • Description: Retrieves all entries between two dates (both inclusive), oldest first. Product lists are omitted unless explicitly requested, since a long range with products is a very large response.
  • Query Parameters:
    • fromDate (required): The start date in YYYY-MM-DD format.
    • toDate (required): The end date in YYYY-MM-DD format.
    • includeProducts (optional): Whether to include each day's product list. Defaults to false.
  • Example: /api/v2/fddbdata/range?fromDate=2024-12-01&toDate=2024-12-31
  • Response: A JSON array of entries, same shape as Retrieve All Data.
  • Error Responses:
    • Returns HTTP 400 Bad Request if fromDate is after toDate.
    • Returns HTTP 400 Bad Request if the range exceeds 366 days.

Search Products by Name ​

GET /api/v2/fddbdata/products?name={product}

  • Description: Retrieves all entries matching the given product name as JSON. The search is fuzzy, allowing for partial matches. Optionally you can restrict results to specific days of the week, a date range, and/or cap the number of results.

  • Query Parameters:

    • name (required): The name of the product to search for.

    • days (optional): One or more day names (ISO weekday names) to filter results by day-of-week. Accepts a comma-separated list of values. Valid values: MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY.

    • fromDate (optional): Restrict matches to this date and later, format: YYYY-MM-DD.

    • toDate (optional): Restrict matches to this date and earlier, format: YYYY-MM-DD.

    • limit (optional): Maximum number of results to return.

      • If days is omitted or empty, the endpoint returns matches for all dates.
      • If one or more days are provided, the endpoint returns only the product occurrences whose date falls on any of the specified weekdays.
  • Examples:

    • All matches for "Strawberry": /api/v2/fddbdata/products?name=Strawberry

    • Matches for "Banana" that occurred on Mondays only: /api/v2/fddbdata/products?name=Banana&days=MONDAY

    • Matches for "Banana" that occurred on Mondays and Saturdays: /api/v2/fddbdata/products?name=Banana&days=MONDAY,SATURDAY

    • Latest 10 matches for "Banana" in 2024: /api/v2/fddbdata/products?name=Banana&fromDate=2024-01-01&toDate=2024-12-31&limit=10

  • Behavior notes:

    • The days parameter uses the standard Java DayOfWeek names (ISO weekdays). Provide the weekday names in uppercase to match the enum values; the OpenAPI spec documents the permitted values.
    • The filtering is performed server-side in the v2 API. The response contains a list of objects with the date and a product object. When filtered by days, only those entries whose date's weekday matches any of the provided days are returned.
  • Response: A JSON array containing all matching entries (see full example response).

    json
    [
      {
        "date": "2023-01-06",
        "product": {
          "name": "Pizza Brot",
          "amount": "150 g",
          "calories": 391.0,
          "fat": 5.1,
          "carbs": 71.1,
          "protein": 15.0,
          "link": "/db/en/food/marziale_pizza_brot/index.html"
        }
      },
      [...]
    ]
  • Error Responses:

    • Returns HTTP 400 Bad Request if fromDate is after toDate.

List Distinct Product Names 2.3.0+ ​

GET /api/v2/fddbdata/products/distinct?search={term}&limit={amount}

  • Description: Lists the distinct product names in the database, so a fuzzy term (e.g. "oats") can be resolved to the exact, brand-prefixed name FDDB stores (e.g. "Haferflocken kernig").

  • Query Parameters:

    • search (optional): Case-insensitive substring the name has to contain. If omitted, all distinct names are considered.
    • limit (optional): Maximum number of names to return (1-1000). Defaults to 100.
  • Example: /api/v2/fddbdata/products/distinct?search=hafer&limit=20

  • Response: A JSON array of matching names in alphabetical order.

    json
    [
      "Haferflocken kernig",
      "Haferflocken zart",
      [...]
    ]

Get Product Summary 2.3.0+ ​

GET /api/v2/fddbdata/products/summary?name={product}&fromDate={startDate}&toDate={endDate}

  • Description: Aggregates every occurrence of the products matching a search term into a single summary: how often they were logged, first and last date, the totals they contributed, and the weekday distribution.

  • Query Parameters:

    • name (required): The product name to search for.
    • fromDate (optional): Restrict the aggregation to this date and later, format: YYYY-MM-DD.
    • toDate (optional): Restrict the aggregation to this date and earlier, format: YYYY-MM-DD.
  • Example: /api/v2/fddbdata/products/summary?name=Haferflocken

  • Response: A JSON object containing the aggregated summary.

    json
    {
      "searchTerm": "haferflocken",
      "matchedProductNames": [
        "Haferflocken kernig",
        "Haferflocken zart"
      ],
      "timesEaten": 42,
      "firstDate": "2024-01-03",
      "lastDate": "2024-12-19",
      "totalCalories": 12600.5,
      "totalFat": 310.2,
      "totalCarbs": 1850.7,
      "totalProtein": 540.3,
      "averageCalories": 300.0,
      "weekdayDistribution": {
        "MONDAY": 8,
        "TUESDAY": 5,
        "WEDNESDAY": 6,
        "THURSDAY": 7,
        "FRIDAY": 6,
        "SATURDAY": 5,
        "SUNDAY": 5
      }
    }
  • Error Responses:

    • Returns HTTP 400 Bad Request if fromDate is after toDate.

Get Top Products 2.3.0+ ​

GET /api/v2/fddbdata/products/top?by={ranking}&fromDate={startDate}&toDate={endDate}&limit={amount}

  • Description: Ranks products by how often they were logged (FREQUENCY) or by the nutrient totals they contributed - "what do I actually eat the most, and where do my calories come from?"

  • Query Parameters:

    • by (optional): Ranking criterion. Valid values: FREQUENCY, CALORIES, FAT, CARBS, PROTEIN. Defaults to FREQUENCY.
    • fromDate (optional): Restrict the ranking to this date and later, format: YYYY-MM-DD.
    • toDate (optional): Restrict the ranking to this date and earlier, format: YYYY-MM-DD.
    • limit (optional): Maximum number of products to return (1-500). Defaults to 20.
  • Example: /api/v2/fddbdata/products/top?by=CALORIES&limit=10

  • Response: A JSON array of ranked products, highest first.

    json
    [
      {
        "name": "Haferflocken kernig",
        "timesEaten": 42,
        "totalCalories": 12600.5,
        "totalFat": 310.2,
        "totalCarbs": 1850.7,
        "totalProtein": 540.3,
        "averageCalories": 300.0
      },
      [...]
    ]
  • Error Responses:

    • Returns HTTP 400 Bad Request if fromDate is after toDate.

Export Data by Date Range ​

POST /api/v2/fddbdata

  • Description: Exports all entries within a specified date range.

  • Request Body:

    • fromDate (required): The start date in YYYY-MM-DD format.
    • toDate (required): The end date in YYYY-MM-DD format.
  • Example Payload:

    json
    {
      "fromDate": "2021-05-13",
      "toDate": "2021-08-18"
    }
  • Response: A JSON object containing the data:

    json
    {
      "successfulDays": [
        "2024-08-30",
        "2024-08-31"
      ],
      "unsuccessfulDays": [
        "2024-08-29"
      ]
    }
  • Error Responses:

    • Returns HTTP 400 Bad Request if fromDate is after toDate.
    • Returns HTTP 409 Conflict if another export is already running - see only one export at a time. The request is not queued; retry it once the running export has finished.
    • Returns HTTP 502 Bad Gateway if logging in to fddb.info fails.

Export Data for Last N Days ​

GET /api/v2/fddbdata/export?days={amount}&includeToday={bool}

  • Description: Exports entries for the last specified number of days.

  • Query Parameters:

    • days (required): The number of days to export.
    • includeToday (optional): Whether to include the current day in the export. (true or false)
  • Example: /api/v2/fddbdata/export?days=5&includeToday=true

  • Response: A JSON object containing the data:

    json
    {
      "successfulDays": [
        "2024-08-30",
        "2024-08-31"
      ],
      "unsuccessfulDays": [
        "2024-08-29"
      ]
    }
  • Error Responses:

    • Returns HTTP 400 Bad Request if days is outside the window configured by FDDB-EXPORTER_FDDB_MIN-DAYS-BACK and FDDB-EXPORTER_FDDB_MAX-DAYS-BACK (1-365 by default).
    • Returns HTTP 409 Conflict if another export is already running - see only one export at a time. The request is not queued; retry it once the running export has finished.
    • Returns HTTP 502 Bad Gateway if logging in to fddb.info fails.

Retrieve Stats to Data ​

GET /api/v2/stats

  • Description: Retrieve the stats to the saved data.

  • Note: The last7DaysAverage and last30DaysAverage fields have been removed from this endpoint. Use the new rolling averages endpoint for flexible period-based averages.

  • Note: mostRecentMissingDay, missingDaysCount, currentStreak and longestStreak require querying individual entries rather than aggregated totals, and are null when those figures could not be computed. currentStreak only counts today once it has an entry, so a day still in progress does not break the streak.

  • Note: mostRecentMissingDay is a date or null 2.5.0+. Before 2.5.0 it also carried the string only available with MongoDB. null means either that there is no missing day or that the coverage figures could not be computed — missingDaysCount tells the two apart, being 0 in the first case and null in the second.

  • Response: A JSON object containing the data (see example response).

    json
    {
      "amountEntries": 606,
      "firstEntryDate": "2023-01-01",
      "lastEntryDate": "2024-12-22",
      "mostRecentMissingDay": "2024-12-20",
      "missingDaysCount": 18,
      "currentStreak": 2,
      "longestStreak": 94,
      "entryPercentage": 95.1,
      "uniqueProducts": 150,
      "averageTotals": {
        "avgTotalCalories": 2505.7,
        "avgTotalFat": 125.7,
        "avgTotalCarbs": 204.4,
        "avgTotalSugar": 63.4,
        "avgTotalProtein": 118.0,
        "avgTotalFibre": 18.4
      },
      "highestCaloriesDay": {
        "date": "2024-07-31",
        "total": 5317.0
      },
      "highestFatDay": {
        "date": "2023-09-23",
        "total": 260.3
      },
      "highestCarbsDay": {
        "date": "2024-07-31",
        "total": 501.7
      },
      "highestProteinDay": {
        "date": "2024-08-03",
        "total": 234.1
      },
      "highestFibreDay": {
        "date": "2023-05-09",
        "total": 53.8
      },
      "highestSugarDay": {
        "date": "2023-10-21",
        "total": 220.4
      }
    }

Retrieve Rolling Averages ​

GET /api/v2/stats/averages?fromDate={startDate}&toDate={endDate}

  • Description: Retrieve rolling averages for a specified date range. This endpoint calculates averages for all entries between the from and to dates (inclusive).

  • Query Parameters:

    • fromDate (required): The start date in YYYY-MM-DD format.
    • toDate (required): The end date in YYYY-MM-DD format.
  • Example: /api/v2/stats/averages?fromDate=2024-01-01&toDate=2024-01-31

  • Response: A JSON object containing the rolling averages (see example response).

    json
    {
      "fromDate": "2024-01-01",
      "toDate": "2024-01-31",
      "averages": {
        "avgTotalCalories": 3054.4,
        "avgTotalFat": 123.9,
        "avgTotalCarbs": 303.7,
        "avgTotalSugar": 85.6,
        "avgTotalProtein": 136.8,
        "avgTotalFibre": 25.8
      }
    }
  • Error Responses:

    • Returns HTTP 400 Bad Request if fromDate is after toDate.
    • Returns HTTP 400 Bad Request if dates are not in the format YYYY-MM-DD.

Get a Trend Time Series 2.3.0+ ​

GET /api/v2/stats/trend?metric={metric}&fromDate={startDate}&toDate={endDate}&granularity={granularity}

  • Description: Builds a time series of one metric over a date range, bucketed by day, ISO week or month. Buckets without a single entry are omitted, so unlogged days never drag an average down.

  • Query Parameters:

    • metric (optional): Metric to trend. Valid values: CALORIES, FAT, CARBS, SUGAR, PROTEIN, FIBRE. Defaults to CALORIES.
    • fromDate (required): The start date in YYYY-MM-DD format.
    • toDate (required): The end date in YYYY-MM-DD format.
    • granularity (optional): Bucket size. Valid values: DAY, WEEK (ISO week, Monday-Sunday), MONTH. Defaults to DAY.
  • Example: /api/v2/stats/trend?metric=CALORIES&fromDate=2024-01-01&toDate=2024-03-31&granularity=WEEK

  • Response: A JSON array of buckets in chronological order. For DAY granularity, average and total are identical and dayCount is 1.

    json
    [
      {
        "bucket": "2024-W03",
        "fromDate": "2024-01-15",
        "toDate": "2024-01-21",
        "dayCount": 7,
        "average": 2143.7,
        "total": 15005.9
      },
      [...]
    ]
  • Error Responses:

    • Returns HTTP 400 Bad Request if fromDate is after toDate.

Get a Weekday Breakdown 2.3.0+ ​

GET /api/v2/stats/weekdays?fromDate={startDate}&toDate={endDate}

  • Description: Averages the daily totals grouped by day of the week - "do my weekends wreck the average?". Days of the week without a single entry are omitted.

  • Query Parameters:

    • fromDate (optional): Restrict the aggregation to this date and later, format: YYYY-MM-DD.
    • toDate (optional): Restrict the aggregation to this date and later, format: YYYY-MM-DD.
  • Example: /api/v2/stats/weekdays?fromDate=2024-01-01&toDate=2024-12-31

  • Response: A JSON array of averages per day of the week, Monday first.

    json
    [
      {
        "dayOfWeek": "MONDAY",
        "dayCount": 48,
        "averages": {
          "avgTotalCalories": 2400.1,
          "avgTotalFat": 110.3,
          "avgTotalCarbs": 190.2,
          "avgTotalSugar": 55.4,
          "avgTotalProtein": 120.5,
          "avgTotalFibre": 17.8
        }
      },
      [...]
    ]
  • Error Responses:

    • Returns HTTP 400 Bad Request if fromDate is after toDate.

Get the Macro Split 2.3.0+ ​

GET /api/v2/stats/macro-split?fromDate={startDate}&toDate={endDate}

  • Description: Share of energy from fat, carbs and protein over a date range. The split is kcal-weighted (fat 9 kcal/g, carbs and protein 4 kcal/g), not gram-weighted. Because of that, macroCalories is derived from the macros and will usually differ slightly from averageCalories, which is the calorie figure FDDB itself reports.

  • Query Parameters:

    • fromDate (required): The start date in YYYY-MM-DD format.
    • toDate (required): The end date in YYYY-MM-DD format.
  • Example: /api/v2/stats/macro-split?fromDate=2024-01-01&toDate=2024-01-31

  • Response: A JSON object containing the macro split.

    json
    {
      "fromDate": "2024-01-01",
      "toDate": "2024-01-31",
      "fatPercentage": 34.5,
      "carbsPercentage": 45.2,
      "proteinPercentage": 20.3,
      "fatCalories": 690.3,
      "carbsCalories": 904.8,
      "proteinCalories": 406.4,
      "macroCalories": 2001.5,
      "averageCalories": 2000.5
    }
  • Error Responses:

    • Returns HTTP 400 Bad Request if fromDate is after toDate.

List Missing Days 2.3.0+ ​

GET /api/v2/stats/missing-days?fromDate={startDate}&toDate={endDate}

  • Description: Lists every day in the range that has no entry at all or an entry without a single calorie - "when did I forget to log?"

  • Query Parameters:

    • fromDate (required): The start date in YYYY-MM-DD format.
    • toDate (required): The end date in YYYY-MM-DD format.
  • Example: /api/v2/stats/missing-days?fromDate=2024-01-01&toDate=2024-01-31

  • Response: A JSON array of missing dates in chronological order.

    json
    [
      "2024-01-05",
      "2024-01-12",
      [...]
    ]
  • Error Responses:

    • Returns HTTP 400 Bad Request if fromDate is after toDate.

Download Data in Various Formats ​

GET /api/v2/fddbdata/download

  • Description: Download your FDDB data in CSV or JSON format. This endpoint allows you to export your nutritional data for further analysis or backup purposes. You can choose to download all data or filter by a specific date range, include product details or just daily totals, and customize CSV formatting options.

  • Query Parameters:

    • fromDate (optional): Start date for filtering (inclusive), format: YYYY-MM-DD. If not provided, downloads from the beginning.
    • toDate (optional): End date for filtering (inclusive), format: YYYY-MM-DD. If not provided, downloads until the most recent entry.
    • format (required): Download format. Valid values: CSV, JSON.
    • includeProducts (optional): Whether to include product details (true) or just daily totals (false). Defaults to false.
    • decimalSeparator (optional): Decimal separator for CSV format. Valid values: comma, dot. Defaults to comma. Only applicable when format is CSV.
  • Examples:

    • Download all data as CSV with daily totals only: /api/v2/fddbdata/download?format=CSV&includeProducts=false

    • Download data for January 2024 as JSON with product details: /api/v2/fddbdata/download?fromDate=2024-01-01&toDate=2024-01-31&format=JSON&includeProducts=true

    • Download all data as CSV with dot decimal separator and product details: /api/v2/fddbdata/download?format=CSV&includeProducts=true&decimalSeparator=dot

  • Response: Binary file download with appropriate content type and filename. The filename is automatically generated based on the selected parameters (e.g., fddb-export-2024-01-01-to-2024-01-31-with-products.csv).

  • CSV Format:

    • Daily totals only (includeProducts=false): Each row represents one day with columns for date, total calories, total fat, total carbs, total sugar, total protein, and total fiber.
    • With product details (includeProducts=true): Each row represents one product consumed on a specific date, including all nutritional values and product information.
  • JSON Format:

    • Returns data in the same structure as the /api/v2/fddbdata endpoint, but filtered by the specified date range if provided.

Maximum download size 2.5.0+ ​

A single download may cover at most 365 days (roughly one year of daily logging). The whole result is held in memory while it is being formatted, so an open-ended request is not allowed to grow without limit along with the database.

Requests above the limit are refused with HTTP 413 Payload Too Large and a plain-text body naming the number of days found and the limit, for example:

This download would cover 500 days, which is more than the maximum of 365 days per download. Narrow the range with
the fromDate and toDate parameters and download the data in several parts.

The limit applies to the number of days returned, not to a fixed time span: pass fromDate and toDate to download a larger diary in several parts. There is no cap on how far apart those two dates may be, only on how many days the result contains.

  • Error Responses:
    • Returns HTTP 400 Bad Request if fromDate is after toDate.
    • Returns HTTP 400 Bad Request if an invalid format, decimalSeparator, or date format is provided.
    • Returns HTTP 503 Service Unavailable with This operation requires MongoDB to be enabled if MongoDB is disabled. The download reads individual entries, which only MongoDB stores. was 400 before 2.5.0
    • Returns HTTP 413 Payload Too Large if the request covers more than 365 days (see above).

Migrate MongoDB data to InfluxDb ​

POST /api/v2/migration/toInfluxDb

  • Description: Migrates existing data from MongoDB to InfluxDb.
  • Response: HTTP 200 if successful.

Released under the MIT + Commons Clause License.