Custom fields
Summary
Problem statement
While the protocol defines a minimum set of fields that are consistent across all implementations, it should also provide a consistent mechanism for defining custom fields that may be shared by some, but not all, implementations.
How can the specification allow developers to define custom fields for their own implementations, while also enabling other implementations to re-use them?
Sub-questions
- Should custom fields have a single
value
property with an associatedtype
, or multiple type-based properties (e.g.,stringValue
,arrayValue
)? - Should the
customFields
property be an array ofCustomField
models? Or an object where each value is aCustomField
model? - How can we minimize naming collisions while supporting reusability and extensibility?
Decision drivers
- Custom fields are defined in a way that is largely self-documenting.
- API consumers can reliably (de)serialize the values of custom fields across programming languages and implementations.
- Custom fields can be re-used across multiple implementations.
- The likelihood of naming collisions is low even when combining data from multiple implementations.
Decision outcome
We decided to define a CustomObject
model as an object that has a:
- A required
name
property - Single
value
property that can be any type (including nested objects or arrays) - A
type
property that supports the following options (JSON schema types):string
number
boolean
array
object
- An optional
schema
property that is a URL to a valid JSON schema that can be used to validate the contents of thevalue
property - An optional
description
property
Additionally custom fields within a given model should be defined in a customFields
property. This property should be an object where each value is an instance of CustomField
and each key follows a consistent naming convention (e.g. namespaces or prefixes) that minimize the likelihood of naming collisions.
Here’s an example of a potential model that follows this approach:
{ "name": "Example grant", "description": "Description about this grant", "customFields": { "gov.grants@agency": { "name": "Agency", "type": "string", "value": "Department of Transportation", "description": "The government department or agency managing the grant opportunity" }, "gov.grants@eligibility": { "name": "eligibility", "type": "array", "value": ["Individuals", "City or township governments"], "schema": "https://example-schema-store.org/eligibility.yaml" } }}
Consequences of single value
field
- Positive consequences
- Simplifies the model while accommodating various data types.
- Supports adding new types or schemas without adding new properties.
- Leverages existing standards for validation and documentation.
- Negative consequences
- Makes parsing values in statically typed languages slightly more complex.
Consequences of customFields
object vs. array
- Positive consequences
- Enables implementations to require certain custom fields in their spec.
- Easier to define in TypeSpec, JSON Schema, and OpenAPI specs.
- Makes (de)serializing custom fields more predictable.
- Negative consequences
- Increases the likelihood of naming collisions.
- Requires conventions like namespacing keys to reduce this risk.