Discriminators
When defining a Union Schema, a unionDiscriminator handler is used to decide
which alternative union schema to use.
Discriminators may need to inspect values in the output target value, which means they need to either use
prebuilt keywords like $reference to get these values, or they often need to be implemented as a function
using the full value processor signature.
If the discriminator returns undefined, it means the union schema cannot yet be resolved, and discrimination
will be retried on another traversal pass.
Upon success, the discriminator should return a reference to the resolved schema, either the key of the
unionSchema, or the actual CompiledSchema value. (Note: not the pre-compilation Schema!)
import { Schema, SchemaResolver } from '@versionzero/schema';
const resolver = new SchemaResolver();
const schema = await resolver.compile(
new Schema()
.unionDiscriminator(data => {
const contentType = data?.['content-type'];
if (!contentType) {
return undefined;
}
if (/.+\/.*json/.test(contentType)) {
return 'json';
}
else if (contentType.startsWith('text/')) {
return 'text'
}
else {
return 'data';
}
})
.unionSchema('text', new Schema('object')
.property('content-type', new Schema('string')
.default('text/plain')
)
.property('content', new Schema('string'))
)
.unionSchema('json', new Schema('object')
.property('content-type', new Schema('string')
.required()
.normalizer({$literal: 'application/json'})
)
.property('content', new Schema('string').validator('$json'))
)
.unionSchema('data', new Schema('object')
.property('content-type', new Schema('string').required())
.property('content', new Schema('string').validator('$base64'))
)
);
console.log( await schema.process( {'content-type': 'text/plain', content: 'hello' }) );
console.log( await schema.process( {'content-type': 'application/foo+json', content: '{"stuff":123}'}))
console.log( await schema.process( {'content-type': 'application/octet-stream', 'content': 'SGVsbG8sIFdvcmxkIQ=='}))
Automatic Discrimination
It isn't always necessary to provide a unionDiscriminator handler if the compiler determines that
one can be automatically synthesized:
- If the union schemas all contain unique properties.
- If the union schemas contain common properties that are constrained to unique values.
In these cases, the discriminator will be created during compilation, and the referenced properties will be "hoisted" to the containing schema in order to make them available for assignment before resolution.
Alternatives
Unions are
See the Union guide and the examples in the project repo for more details.