Featurevisor
See all posts

Complex variables

By Fahad Heylaal on

Feature variables with object and array types can now be expressed as more complex data structures with full type safety and code generation.

Challenges with existing variable types

Featurevisor always supported several different types of variables in features, including:

  • boolean: true or false values
  • string: text strings
  • integer: whole numbers without decimal places
  • double: numbers with decimal places
  • array: array of strings only
  • object: flat objects only
  • json: any valid JSON in stringified form, when no other type is suitable

The moment you enter the territory of object and array types, you are limited to very simple data structures like either an array of strings, or a flat object.

This posed a challenge when you wanted to express more complex data structures including nested objects or arrays of objects. You are left with the only option of using the json type, which is a stringified JSON object prone to human errors.

Solution: typed objects and arrays

Define nested objects and arrays with schemas, and use linting to check that values match those schemas.

The expressions below use a flavour of JSON Schema to define the shapes more precisely.

Variable type: object

Keep using flat objects, or describe more complex objects with properties.

Implicit flat object

Just like before, if you define an object with no extra schema, it will be treated as a flat object:

features/my_feature.yml
# ...
variablesSchema:
my_object:
type: object
defaultValue:
myKey: my value
anotherKey: another value

Explicit flat object

Define the object's schema with properties:

features/my_feature.yml
# ...
variablesSchema:
my_object:
type: object
properties: # define the shape of the object here
myKey:
type: string
anotherKey:
type: string
defaultValue:
myKey: my value
anotherKey: another value

With properties defined, linting reports values that do not match the schema anywhere in the feature definition.

Nested objects

Define nested objects with their own properties:

features/my_feature.yml
# ...
variablesSchema:
my_object:
type: object
properties:
myKey:
type: string
nestedObject:
type: object
properties:
nestedKey:
type: string
defaultValue:
myKey: my value
nestedObject:
nestedKey: nested value

Evaluating object variables

SDK usage remains the same as before:

your-app/index.ts
const f; // Featurevisor SDK instance
// without explicitly using TypeScript interfaces
const myObjectValue = f.getVariable('my_feature', 'my_object');
const nestedObjectValue = f.getVariable('my_feature', 'nested_object');
// with TypeScript interfaces
const myObjectValue = f.getVariableObject<MyObject>('my_feature', 'my_object');
const nestedObjectValue = f.getVariableObject<NestedObject>('my_feature', 'nested_object');

Variable type: array

Keep using arrays of strings, or describe other item types with items.

Implicit array

Just like before, if you define an array with no extra schema, it will be treated as an array of strings:

features/my_feature.yml
# ...
variablesSchema:
my_array:
type: array
defaultValue:
- red
- blue
- green

Explicit array type

Define the array's item type with items:

features/my_feature.yml
# ...
variablesSchema:
my_array:
type: array
items:
type: string
defaultValue:
- red
- blue
- green

Array of objects

Define an array of objects with items:

features/my_feature.yml
# ...
variablesSchema:
my_array:
type: array
items:
type: object
properties:
color:
type: string
opacity:
type: integer
defaultValue:
- color: red
opacity: 100
- color: blue
opacity: 50
- color: green
opacity: 25

Evaluating array variables

SDK usage remains the same as before:

your-app/index.ts
const f; // Featurevisor SDK instance
// without explicitly using TypeScript interfaces
const myArrayValue = f.getVariable('my_feature', 'my_array');
// with TypeScript interfaces
const myArrayValue = f.getVariableArray<MyArrayItem>('my_feature', 'my_array');

Code generation

The CLI can generate TypeScript types from your feature definitions for use in applications.

This keeps your application types in step with the definitions.

Generate the types:

Command
npx featurevisor generate-code \
--language=typescript \
--out-dir=src

Learn more in code generation page.

How to upgrade

This change does not break existing usage, but it is recommended that your applications upgrade to the latest SDKs first for maximum compatibility.

Conclusion

Featurevisor started with some very carefully crafted variable types to cover the most common use cases. However, as your application and its architecture grows, you may find yourself needing to express more complex data structures including nested objects or arrays of objects.

This is now possible with the improvements introduced in this release.

Use schemas to make the expected shape of that configuration part of your definition.