Field Behavior
This package provides primitives for implementing AIP field behavior annotations as described by AIP-203.
Clearing Fields by Behavior
Section titled “Clearing Fields by Behavior”Clear fields with specific field behaviors from a message. For instance, clear all OUTPUT_ONLY fields before processing a request:
import { clearFields } from "@protoutil/aip/fieldbehavior";import { FieldBehavior } from "@buf/googleapis_googleapis.bufbuild_es/google/api/field_behavior_pb.js";
const message = create(MyMessageSchema, { ... });const updated = clearFields(MyMessageSchema, message, [FieldBehavior.OUTPUT_ONLY]);By default, this function returns a copy of the original message with the fields cleared. Pass { mutate: true } to mutate the original message instead.
Querying Field Behaviors
Section titled “Querying Field Behaviors”import { getFieldBehavior, hasFieldBehavior, hasAnyFieldBehavior } from "@protoutil/aip/fieldbehavior";
// Get the field behaviors for a specific fieldconst behaviors = getFieldBehavior(fieldDescriptor);
// Check if a field has a specific behaviorhasFieldBehavior(fieldDescriptor, FieldBehavior.REQUIRED); // true/false
// Check if a field has any of the specified behaviorshasAnyFieldBehavior(fieldDescriptor, [FieldBehavior.REQUIRED, FieldBehavior.IMMUTABLE]);Validating Immutable Fields
Section titled “Validating Immutable Fields”Validate that no immutable fields have been changed on a message:
import { validateImmutableFields } from "@protoutil/aip/fieldbehavior";
validateImmutableFields(MyMessageSchema, message); // throws if any immutable fields are setWith a field mask to only check specific fields:
import { fieldMask } from "@protoutil/core/wkt";
validateImmutableFields(MyMessageSchema, message, { fieldMask: fieldMask(MyMessageSchema, ["immutable_field"]),});Validating Required Fields
Section titled “Validating Required Fields”Similarly, validate that all required fields have been set:
import { validateRequiredFields } from "@protoutil/aip/fieldbehavior";
validateRequiredFields(MyMessageSchema, message); // throws if any required fields are missingvalidateRequiredFields(MyMessageSchema, message, { fieldMask: mask }); // checks only masked fieldsBuilding Field Masks from Behaviors
Section titled “Building Field Masks from Behaviors”Build a FieldMask that excludes fields with specific behavior annotations. This is useful for constructing default read or update masks for a repository or service layer.
import { fieldMaskFromBehavior, outputOnlyMask, inputOnlyMask, immutableMask } from "@protoutil/aip/fieldbehavior";import { FieldBehavior } from "@buf/googleapis_googleapis.bufbuild_es/google/api/field_behavior_pb.js";
// Exclude OUTPUT_ONLY fields (useful for write operations)const writeMask = outputOnlyMask(MyMessageSchema);
// Exclude INPUT_ONLY fields (useful for read operations)const readMask = inputOnlyMask(MyMessageSchema);
// Exclude IMMUTABLE fields (useful for update operations)const updateMask = immutableMask(MyMessageSchema);
// Exclude multiple behaviors at onceconst mask = fieldMaskFromBehavior(MyMessageSchema, [ FieldBehavior.OUTPUT_ONLY, FieldBehavior.IMMUTABLE,]);The function recursively traverses nested message, repeated message, and map-of-message fields, producing dotted paths (e.g. parent.field) and wildcard paths for collections (e.g. children.*.field). A maxDepth option (default: 5) controls recursion depth and handles self-referential schemas. When the limit is reached, the parent field path is included as-is, preserving the entire subtree.
// Control recursion depthconst shallow = outputOnlyMask(MyMessageSchema, { maxDepth: 0 }); // top-level fields onlyconst deep = outputOnlyMask(MyMessageSchema, { maxDepth: 3 }); // recurse up to 3 levelsAPI Reference
Section titled “API Reference”| Export | Description |
|---|---|
clearFields(schema, message, behaviors, opts?) | Clear fields matching the given behaviors. Options: { mutate? }. Returns a copy unless mutate is true. |
fieldMaskFromBehavior(schema, exclude, opts?) | Build a FieldMask excluding fields with any of the specified behaviors. Recurses into nested messages. Options: { maxDepth? }. |
getFieldBehavior(field) | Get the list of FieldBehavior annotations for a field descriptor. |
hasFieldBehavior(field, behavior) | Check if a field has a specific FieldBehavior. |
hasAnyFieldBehavior(field, behaviors) | Check if a field has any of the specified FieldBehavior values. |
immutableMask(schema, opts?) | Shorthand for fieldMaskFromBehavior(schema, [IMMUTABLE], opts). |
inputOnlyMask(schema, opts?) | Shorthand for fieldMaskFromBehavior(schema, [INPUT_ONLY], opts). |
outputOnlyMask(schema, opts?) | Shorthand for fieldMaskFromBehavior(schema, [OUTPUT_ONLY], opts). |
validateImmutableFields(schema, message, opts?) | Throws if any IMMUTABLE fields are set. Options: { fieldMask? }. |
validateRequiredFields(schema, message, opts?) | Throws if any REQUIRED fields are missing. Options: { fieldMask? }. |