Files
backend_fiesta/models/nutrition.go
2026-09-29 22:40:36 +05:30

53 lines
2.4 KiB
Go

package models
/*
The nutrition panel, as the customer app renders it.
The figures come from the catalogue-intelligence service — the same one behind
the health score card in the console — and this is the shape they reach the app
in. See services/nutritionService.go for the fetch and the mapping.
── Why the field names are ugly ────────────────────────────────────────────
`servingsize`, not `serving_size` or `servingSize`. This is the shape the app
developer asked for, and an API is a promise to a client already written against
it. Consistency with the rest of Fiesta — itself inconsistent, `productid`
beside `image_id` beside `sku_source` — is worth less than not breaking the
caller.
*/
type NutritionPanel struct {
// What the figures are measured against. "100g" for everything the service
// returns today: its top-level values are per 100g, which is what the
// console's own panel prints beneath them.
Per string `json:"per,omitempty"`
// What the pack calls one serving — "1 mini (11 g)". Absent when the
// service did not state one, rather than defaulted: a serving size is a
// claim about the food, and a guessed one is a false claim.
Servingsize string `json:"servingsize,omitempty"`
// Never nil when this panel exists — see HasValues. An app receiving
// `items: null` has to branch; one receiving `[]` does not, and a panel with
// no rows should not have been sent at all.
Items []NutritionItem `json:"items"`
}
// NutritionItem is one line of the panel.
type NutritionItem struct {
Name string `json:"name"`
// The figure. A float because saturated fat is 18.7g as often as it is 19g,
// and rounding it to please a type would be editing a label.
Value float64 `json:"value"`
// "kcal", "g", "mg". Free text on purpose: `extended_nutrients` carries its
// own units from the source, and a closed list here would mean refusing to
// carry whatever the label actually says.
Unit string `json:"unit,omitempty"`
}
// HasValues reports whether this panel is worth sending.
//
// A panel with no rows is not a panel — it is an empty box on a product page,
// which a shopper reads as "this food has no nutrition" rather than "we do not
// know yet". The endpoint omits it instead.
func (p *NutritionPanel) HasValues() bool {
return p != nil && len(p.Items) > 0
}