The Problem

Every time our application receives some data input via an application boundary at runtime, it should be at least validated against a data scheme. In typed languages like Typescript, it also makes sense to map the input data to a known type after validation. Examples for such input data would be files uploaded from the file system, REST response bodies or serialized database entries. How can we deal with this task in an efficient, elegant and transparent way?

Alternative Solutions

There are three popular approaches in the domain of runtime typing and validation. They differ mostly regarding the point of time when the validations actually happens and how the user can define the rules.

  • Schema files: this approach defines a data schema in a standardized schema file and validates the input against this schema on runtime. JSON schema is a popular example for this approach (https://json-schema.org/). Advantages are that most schema formats are quite expressive and files can easily be versioned. On the contrary, type definitions must be derived from the schema file at build/ compile time and can therefore lead to duplication and poor reusability. Moreover, schema files needs to be loaded at runtime and cannot easily be shared or exported.
  • Class decorators: this approach defines data representations as classes and adds validation decorators to its fields. class-decorator is a popular example for this approach (https://github.com/typestack/class-validator). At runtime, data fields are validated when a new instance should be created. Advantages are the good integration into a class-based application design and the intuitive usage of decorators. On the contrary, plain Javascript/ Typescript objects always need to be transformed into class instances for validation, which makes this approach less suitable when following a class-less application design. Moreover, Typescript has rather less support for reflection which can make validation of nested objects rather complicated.
  • Decoder functions: this approach defines data representations as interfaces and sets up decoder functions for object validation and transformation. io-ts is a popular example for this approach (https://gcanti.github.io/io-ts/). Advantages are the good support of type-based application design, where validation and types are defined together in one place. On the contrary, there is less support for classes and most libraries follow a strict functional programming approach, which sometimes feels unnatural within an imperative application design.

#typescript #validation #iot

Typescript Runtime Validation With io-ts
1.60 GEEK