Featurevisor
See all posts

Reusable schemas

By Fahad Heylaal on

Recently, Featurevisor introduced more complex data structures in variables supporting nested objects, and also arrays of objects with full type safety.

Now those schemas (optionally) can be defined once separately, and referenced from anywhere by name.

TL;DR: read full API for reusable schemas here.

How variables are defined today

Each feature maintains its own variables' schema definitions.

The types of variables supported today include:

  • string
  • boolean
  • integer
  • double
  • array
  • object
  • json (any valid JSON in stringified form)

Here's a simple example of a string variable

features/my_feature.yml
# ...
variablesSchema:
my_variable:
type: string
defaultValue: red

Variables may also be complex data structures in the form of:

  • objects (flat or nested), or
  • arrays (of strings, objects, or more):

Here's an example of a nested object variable:

features/my_feature.yml
# ...
variablesSchema:
my_nested_object_variable:
type: object
properties:
my_property:
type: string
another_property:
type: object
properties:
another_nested_property:
type: string
required:
- my_property
- another_property
defaultValue:
my_property: my value
another_property:
another_nested_property: nested value

Challenges with current approach

When your application configuration grows, you may find yourself repeating the same schema definitions across multiple features, and also across multiple variables.

This also means your individual feature definitions become harder to read and maintain as they grow longer and longer.

Solution: reusable schemas

Instead of having to inline the schema in each feature, we can optionally choose to extract them to separate files and reference them by name.

First we create a schema in schemas directory, following a simplified flavour of JSON Schema:

schemas/my_schema.yml
description: My schema
type: object
properties:
my_property:
type: string
another_property:
type: object
properties:
another_nested_property:
type: string
required:
- my_property
- another_property

And then we can reference it from any feature:

features/my_feature.yml
# ...
variablesSchema:
my_nested_object_variable:
schema: my_schema
defaultValue:
my_property: my value
another_property:
another_nested_property: nested value

Advanced usage

Several other JSON Schema inspired properties are supported, including:

PropertyApplies toDescription
requiredobjectDefine the properties that are required in the schema
minimuminteger, doubleDefine the minimum value for a particular property in the schema
maximuminteger, doubleDefine the maximum value for a particular property in the schema
minLengthstringDefine the minimum length of a string
maxLengthstringDefine the maximum length of a string
patternstringDefine a regular expression pattern that the string value must match
minItemsarrayDefine the minimum number of items in an array
maxItemsarrayDefine the maximum number of items in an array
uniqueItemsarrayRequire that all items in an array are unique (no duplicates)
constanyDefine a constant value for a particular property in the schema
enumanyDefine a list of allowed values for a particular property in the schema
oneOfanyAllow a value to match exactly one of several schemas

Learn more here.

Full linting support

As complexity grows, and you define the schemas more precisely, Featurevisor's linting will help you find issues early if you mistakenly provided any wrong value for the variables anywhere in your feature definitions.

Command
$ npx featurevisor lint

Looking forward

All of this paves the way for more complex variable definitions with full type safety and code generation.

More advanced use cases utilizing these new functionalities are coming soon as guides.

Fun fact: if I didn't build Eventvisor last summer, I probably wouldn't think of bringing schemas into Featurevisor like how it's done here now.

Further reading