Skip to content

Schema keys and error keys

For a model User, the generator emits two records: UserSchemaKeys and UserErrorKeys. Both have one field per schema field, named after the Dart parameter. They differ in what the field holds. The examples use the User and Address models from What gets generated.

Each field of UserSchemaKeys holds the key of that field in the input map: the parameter name, or the name the serializer uses after @JsonKey(name:), fieldRename, @MappableField(key:) or caseStyle. The generated schema is written with these keys, and you can use them to read the raw map without repeating the string.

lib/user.g.dart
const UserSchemaKeys = (
name: "name",
email: "email_address",
age: "age",
role: "role",
address: "address",
);
final raw = json[UserSchemaKeys.email]; // json['email_address']

Each field of UserErrorKeys holds the error path of that field, the string you would pass to getError. A field whose type is another model becomes a nested record: its $key is the field’s own path, and the other entries carry the prefix, so the record mirrors the flat error map.

lib/user.g.dart
const UserErrorKeys = (
name: "name",
email: "email_address",
age: "age",
role: "role",
address: (
$key: "address",
street: "address.street",
city: "address.city",
postcode: "address.postcode",
),
);

Use them with getError:

switch ($UserValidate(json)) {
case ValidationSuccess(:final data):
save(data);
case ValidationFailure():
final emailError = result.getError(UserErrorKeys.email);
final postcodeError = result.getError(UserErrorKeys.address.postcode);
final addressError = result.getError(UserErrorKeys.address.$key);
}
email, address.postcode, address.$key, UserSchemaKeys.email, UserErrorKeys.address.$key
email_address must be a valid email address
postcode must match the pattern ^\d{5}$
null
email_address
address

address.$key is null here because the address failed in a field, not as a whole. It is the path to use for address must be a map or for an object-level rule on Address.

Rename postcode in Address and UserErrorKeys.address.postcode stops compiling, which is the point. A string literal would have kept compiling and started returning null.

A field whose type is a list or map of models holds a plain path, because the index or key is only known at runtime. Build the rest yourself:

// OrderErrorKeys.items is "items"; the index is only known at runtime.
result.getError('items.1.qty');

When a model refers to itself, the nested record would be infinite. The generator emits the plain path for the recursive field instead:

NodeErrorKeys.children, NodeErrorKeys.parent
children
parent

UserSchemaKeys appears in $UserSchema. UserErrorKeys is for your code. Neither record has a named type; both are anonymous Dart records, so let inference carry them or spell the record type out where you pass them around.