Suppose you would like to perform multiple validations on your data before you write it to the database or some other store. Some likely constraints are as follows:

You would like all of the validations to pass before any data is written

If there are multiple validation errors, you would like to receive all of them

It should be possible to easily compose such actions out of smaller parts

In a relational database, there is a simple solution which satisfies the constraints: open a transaction, perform all validations and writes in the transaction, and commit. We can interleave writes with validations, because any failure to validate will roll back all writes.

While the transactional approach is probably the right way in most cases, there can be cases where we might be happier with a less robust design, and willing to trade off some correctness for flexibility. For example, we might not even have access to transactions (perhaps we are making API calls, instead of writing directly to the database) or we might want to perform validations in the application code instead of in the database.

I’m going to explain a simple technique we’ve been using at Lumi in these cases.

An initial API

A computation which does some validation and then writes to the database (or performs some other IO) could be described by the following types:

