Is there any way to programmatically build a record, such that various fields may or may not be present?
My reason being I need to do a json encoding on a record, and certain values absolutely must be omitted entirely from the json object for the API to use its default behavior. As such, I want a way to build a record from a base case, and add fields based on a configuration.
# This code will not work, since the `&` operator cannot add fields to a record,
# But this shows the idea of the behavior I'm looking for
buildRequestBody : Client, List Message -> { model: Str, messages: List Message }*
buildRequestBody = \client, messages ->
{ model: client.model, messages }
|> \body -> when client.providerOrder is
NoProviderOrder -> body
ProviderOrder order -> { body & provider: { order } }
|> \body -> when client.temperature is
NoTemperature -> body
Temperature temperature -> { body & temperature }
Any suggestions? Obviously for just 2 options, I could hardcode each permutation, but I anticipate about 8-10 optional fields, which would be a LOT of permutations.
Come to think of it, can an open record even be used as a return type? Maybe that won't even type check...
Yeah using an open record as a return type doesn't usually make sense. If you're returning { model: Str, messages: List Message}*
you're saying that you're returning a record which contains model
, messages
, and any other fields that your caller wants the record to contain. Since your caller could ask for fields that you have no way of producing, such a return type can only mean that the function never returns at all, i.e. it's an infinite loop or a crash
If you basically want a record where some of the fields are optional, you could make the optional fields a tag union like { model: Str, messages: List Message, provider: [Unspecified, Specified Provider], temperature: [Unspecified, Specified Temperature] }
Problem is that when I encode the record as Json, those are going to be present in the encoded json, and If I include the provider: { order: List Str } in the json, I'm going to get a 400 status error from the API. it must be a valid list, or no entry in the json object at all.
This was definitely discussed before, but I would need to do some searching to dig it up
Fundamentally, it requires opaque types will custom encoding that enables encoding a field as nothing
Might even require some decoder changes.
That or you simply have to build different records, pass them to decode, and remerge code paths when you have a list of bytes.
discussion related to this: #contributing > How to handle json null decoding
Checkout https://github.com/lukewilliamboswell/roc-json/blob/main/package/OptionOrNull.roc
@Eli Dowling implemented Optional for this use case.
We should probably add an example which shows how to do this.
Ah! yes, Option
is exactly what I'm looking for. Thanks guys! Brendan, I was really quite afraid that my only option was going to be my own custom encoder. Awesome to see its already included in roc-json. :fire:
Ian McLerran has marked this topic as resolved.
Last updated: Jul 06 2025 at 12:14 UTC