Models: parsing and breaking down data
Pipelines often need to work with structured data — a webhook payload, an API response, a file. Flovello represents that structured data as a model: a named schema you define (an object with fields, or an enum), which flows through your pipeline as a single typed value. This tutorial covers the handful of nodes that create, split apart, and serialise models.
What's a model?
A model is a schema you create under Models in the app — a named set of typed fields, which can nest objects and arrays. Here's the Fields editor on an "Order" model's page once defined, with a customerId, a list of line items, and a total:
Once defined, a model behaves like any other data type: pins can carry a single model value between nodes, typed to that specific model. The rest of this tutorial uses this "Order" model as its running example.
What happens when a field is missing
The dropdown beside each field's type is the one decision that shapes how the rest of your pipeline has to be built. It answers two questions at once, which is why every option names both.
Nullable or non-nullable — is null a value this field accepts at all? A non-nullable field is a promise: it can never hold null, so nothing downstream has to defend against one.
Required, or what it defaults to — what happens when the incoming data doesn't supply the field?
- Required — parsing fails with an error naming the field. For data you cannot proceed without, like
customerIdabove. - Default null — the field becomes null. Only available on a nullable field, since filling null while refusing null is a contradiction.
- Default empty — for arrays and objects: an empty list, or an object whose own fields are filled by their own rules, all the way down. An
itemsarray that defaults to empty means the loop over it runs zero times instead of needing a guard. - Default value — for text, numbers, booleans and enum references: the literal you enter.
quantityabove defaults to1, so arithmetic downstream never has to cope with a missing number.
The nullability half matters because omitting a key and explicitly sending null are two different messages from whoever is calling you:
{ } (key absent) |
{ "quantity": null } |
|
|---|---|---|
Non-nullable, default 1 |
1 |
1 — null isn't accepted, so the default answers |
Nullable, default 1 |
1 |
null — the sender meant it, so it's kept |
| Nullable, required | fails | null |
| Non-nullable, required | fails | fails |
Choosing non-nullable is what buys the guarantee. Reach for nullable when data is genuinely, meaningfully absent — every pin carrying a nullable value is marked with a ? in the editor, at both ends of every connection, so you can see exactly how far a possible null travels, and Is null? and Default if null are there to handle it.
The default also applies when you build a value with Make rather than parse one. A Make pin you leave untouched shows what the model will fill in greyed text — null, [], 1 — instead of a value it isn't going to produce. Click it to set something else, or clear it to go back to the model's default. A required field is the one case Make can't fill for you, so leaving its pin empty raises a warning on the node.
Parsing raw input into a model
Raw input — a request body, a file, an API response — usually arrives as a stream of bytes, not a model. The Parse to model node bridges that gap: pick a model in the inspector and a wire format (JSON, YAML, or XML), and it parses the stream into a typed value of that model. Because parsing can fail on malformed input, Parse to model sits on the execution flow with two branches — success and error — so you can handle bad input explicitly. When the input is a list rather than a single object, an array variant parses the stream into an array of the chosen model instead.
Breaking a model into fields
Once you have a model value, Break splits it apart. Pick the model in the inspector and the node grows one output pin per field, each typed to match — a string field becomes a string pin, a nested model field becomes another model pin you can Break again. Break is pure: it has no execution pins, and its outputs are computed lazily, only when something downstream reads them.
Composing a model from fields
Make is Break's counterpart: pick a model in the inspector and it grows one input pin per field, then emits the assembled model on its value output. Make is also pure — the model is assembled lazily, only when something reads it. Use it whenever a downstream node expects a whole model rather than loose fields, such as before building a request body.
Serialising a model back out
To turn a model back into text or bytes, use Model to string or Model to stream. Both are pure and support JSON, YAML, and XML. Reach for Model to string when you just need the text — for example to log a model with Log message. Reach for Model to stream when the destination is a streaming consumer, such as the body input of an HTTP request — it writes the serialised model straight to the socket without buffering the whole payload as a string first.
Worked example: reading fields from an order webhook
Here's what it looks like to receive an order webhook, parse its body into an "Order" model, and break that model apart into individual fields:
From there, wire customerId into a Log message node. You don't need to wire anything to the Error branch: an unwired execution output already fails the pipeline automatically, so malformed webhooks are surfaced by default. Only wire a Fail node there if you want a more specific failure message than the default.
See also
- Node reference: Models category for the full list of model-related nodes.
- How execution flow works for more on pure nodes and lazy evaluation, which is how Break and Make behave.