Skip to content

docs: OpenAPI documentation for new product nutrition data schema #12132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

Vic142
Copy link
Contributor

@Vic142 Vic142 commented Jul 7, 2025

The API v3 is going to use a new nutrition data schema for products.
In this PR new OpenAPI documentation is created for the new product nutrition data schema (see 2025 - API - Nutrition Facts Schema and API for more information on the new schema).

Every nutrient in the nutrients.txt taxonomy file is added in the nutrient field of the new nutrition schema documentation.

description: |
todo
properties:
nutrient_sets_index:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the selected proposal (see https://docs.google.com/document/d/19ZRrlWJraJm61E6U7AwxQ1uubPDvmSuNfl9F1oLC0Tg/edit?tab=t.0#heading=h.oqf07hovz1m5 ) we decided that we would not include a nutrients_sets_index, but that we would have a separate nutrient_set_preferred set instead

preparation:
type: string
enum:
- as sold
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- as sold
- as_sold

- manufacturer
- usda
- estimate
- preferred
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no "preferred" source for the option we selected

example: "g"
source:
type: string
enum:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the enum there, as some clients could break if we add a new string (e.g. a new database). It may be better to list the possible values in the description, and state that new values may be added.

e.g. an article about how clients could try to handle unexpected valeus in enums in Flutter, but that's a lot of complexity on the client, and each client would need to do it: https://medium.com/@amjadhamdoun0/efficient-enum-handling-in-dart-with-json-converters-5d98dba17c8c

nutrients:
type: object
description: |
All known nutrients for the product.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should indicate that new nutrients are regularly added, and that clients should not break if they encounter an unexpected nutrient.

@@ -0,0 +1,103 @@
type: object
description: |
Quantity of sodium
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Quantity of sodium
Quantity of a nutrient


**Note**: For most use cases, you should not use this unit, as it can change depending on how the value was entered.
Instead use the `<nutrient>_100g` or `<nutrient>_serving` fields, and convert them to the unit you need.
enum:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we should list possible values in an enum, as clients may break if we add a new unit that they do not expect.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll ask for feedback in #api and #productopener

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should I wait for other feedbacks on this before removing the enum ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vic142 I would say no enum there, because you are creating an expectation that won't hold.

enum: ["<", "<=", "~", ">=", ">"]
description: |
todo (this property is optional)
source:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"source" and "source_per" would be only for the nutrient_set_preferred object, not for the objects in the nutrient_sets array

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we must have a separate object product_nutrient_values_sources that we can add to preferred_set definitions (we already use a AllOf declaration)

"�e",
"�dh",
"gpg",
]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about foods sold as whole items? e.g. oranges etc - typically nutrition is given as "each"/ per "item" - in my own app I use "item" for this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@silkgh So far we have not encountered any source of nutrition data that gives nutrition facts per item (unless the item is equal to the serving, and in that case we have a serving quantity in g / ml). Do you have example of products where nutrition facts are listed per item without a specified weight / volume?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I agree that all foods should be recorded in valid, scientific measurements (e.g. per 100g), I find that pretty much all fruits are recorded per item - not saying it's right but it seems to be a thing in the wonderful world of nutrition

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@silkgh you comment better applies to product_nutrition_properties.yaml, per property.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"I find that pretty much all fruits are recorded per item" --> @silkgh are you talking about input data? i.e. that we get from the packaging that 1 apple = 50g of sugars? or about a desired output, that you would like to get the OFF API to tell you that an apple is 50 of sugars?
Because I have never seen a input source that specifies nutrients per item. EU and US law etc. mandate that the nutrition facts are for a specific quantity (which can be equal to 1 serving which is 1 item, but it needs to specifiy how much g it is)

Copy link
Member

@alexgarel alexgarel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the good work @Vic142 !

New nutrients are regularly added.

Clients should not break if they encounter an unexpected nutrient to preserve compatibility.
properties:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, here I would concentrate on main nutrients (energy, salt, sugar, etc) and let people see the rest with taxonomies, because I feel like it will be overwhelming otherwise to read this documentation), and also it makes a duplicate effort with the taxonomy to maintain this. (Otherwise we could seek to generate this file from the taxonomy, but again it would make it far too long a documentation IMO).

We can add a additionalProperty to support SDK generations tools, letting them know there are other values.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a good option to me. We can specficially name only the "mandatory" nutrients for energy-kj, energy-kcal, proteins, fats, saturated-fats, carbohydrates, sugars, fibers and salt. Maybe total_carbohydrates as well, and whatever nutrients are mandatory in the US and Canada (e.g. calcium and a few others)

unit:
type: string
description: |
The unit of the value entered by the contributor (a user or the manufacturer), for the product as sold (not prepared).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it's not determined, it depends in which entry it's used.

Suggested change
The unit of the value entered by the contributor (a user or the manufacturer), for the product as sold (not prepared).
The unit of the value entered by the contributor (a user or the manufacturer), for the product.


**Note**: For most use cases, you should not use this unit, as it can change depending on how the value was entered.
Instead use the `<nutrient>_100g` or `<nutrient>_serving` fields, and convert them to the unit you need.
enum:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vic142 I would say no enum there, because you are creating an expectation that won't hold.

enum: ["<", "<=", "~", ">=", ">"]
description: |
todo (this property is optional)
source:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we must have a separate object product_nutrient_values_sources that we can add to preferred_set definitions (we already use a AllOf declaration)

"�e",
"�dh",
"gpg",
]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@silkgh you comment better applies to product_nutrition_properties.yaml, per property.

description: |
The nutrition data on the package can be per serving, per 100g or per 100ml.
When the data is given per serving, the actual quantity that defines one serving may vary
between products and should be stored in this field.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove the "should be" the API defines things

Suggested change
between products and should be stored in this field.
between products and is stored in this field.

Comment on lines 28 to 30
The nutrition data on the package can be per serving, per 100g or per 100ml.
When the data is given per serving, the actual quantity that defines one serving may vary
between products and should be stored in this field.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: when I break line in markdown I prefer to do it in meaninful places.
Because if you edit this text afterwards, you would have to redo all the line splitting if your text does not fit anymore. So it's better to treat it as code, and make meaningfull lines.
Like:

Suggested change
The nutrition data on the package can be per serving, per 100g or per 100ml.
When the data is given per serving, the actual quantity that defines one serving may vary
between products and should be stored in this field.
The nutrition data on the package can be per serving, per 100g or per 100ml.
When the data is given per serving,
the actual quantity that defines one serving may vary between products
and should be stored in this field.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why changes in this file ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i didn't touch it and the changes don't appear in my branch locally so I don't know how it appeared on GitHub, I'm going to check why it says there were changes

(per 100g, per 100ml or per serving) in a standard unit (g or ml)
allOf:
- $ref: "../schemas/product_nutrient_values.yaml"
- type: object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turn this into a ref to a new product_nutrient_source.yml

Copy link

@teolemon teolemon moved this from To discuss and validate to PRs in 🍊 Open Food Facts Server issues Jul 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API v3 📚 Documentation Documentation issues improve the project for everyone. Nutrition facts
Development

Successfully merging this pull request may close these issues.

4 participants