Composable Object validations in JS
Tags: javascript, functional, ramda
Published: 2018-02-10 22:31:26

---
title: "Composable Object validations in JS"
published: true
tags: javascript,functional,ramda
---

![](https://cdn-images-1.medium.com/max/1024/1*ub06dgVGDo7XeByUxON0-w.jpeg)<figcaption>“Bellas Artes” byÂ me</figcaption>

In my day job, I’m working in a project that consists of a react-native app that is flexible enough to be configured to the needs of many of our clients. A lot of that configuration comes from the server, at runtime. But we also need to configure a lot of things at compile time, mainly assets and variables needed in the native&nbsp;code.

For that end, we have a setup script that receives a configuration file in JSON and makes a bunch of side effects. I realized that if some of these things went wrong, it would silently and fatally affect the JS runtime. So, I decided to implement a validation function of the JSON config file before making any changes, to make sure each config field had the correct&nbsp;type.

I knew this would be complex, because some fields are optional, others are required but only if some other field is set, and so&nbsp;on.

Fortunately, found the perfect abstraction to make this easy and simple. I discovered [Spected](https://github.com/25th-floor/spected).

My first rules looked like&nbsp;this:

```js
const isType = R.curry((type, value) => R.type(value) === type);
const rules = {
  version: [[isType('Number')], 'Version must be a number'],
  build: [[isType('Number')], 'Build must be a number'],
  appName: [[isType('String'), 'appName must be a string']]
}
```

As you can see, we are leveraging the power and [Ramda](http://ramdajs.com/) and [currying](https://www.youtube.com/watch?v=iZLP4qOwY8I) to make amazingly simple validations. But, of course, this is a simplified version. The real-world code had many more rules, and _writing the same kind of message over and over again seemed like something I shouldn’t have to&nbsp;do._

If only I could pass Spected a function to make the error message… Such a function would receive the field name and the type it’s supposed to be and return a nice error message, like&nbsp;this:

```js
const typeMessage = (type, field) => `${field} should be a ${type}`;
```

Looking at Spected source code, I discovered that the error message could already be a function, but it wasn’t passed the field name. So, I submitted a [PR](https://github.com/25th-floor/spected/pull/89) to make that happen, and _VoilÃ _! A whole new world of simple and super-composable validations started to&nbsp;appear!

```js
const typeMessage = (type, field) => `${field} has to be a ${type}`;
const typeRule = type => [
  isType(type),
  (val, field) => typeMessage(type, field)
];
const isString = typeRule("String");
const isNumber = typeRule("Number")

const rules = {
  version: [isNumber],
  build: [isNumber],
  appName: [isString]
}
```

Now you should be convinced of the advantages of such an approach, but I’ll make my point stronger by writing about optional fields. If the config file is missing one of these fields, no problem. But If it’s present, we still want to make sure that the type is&nbsp;valid.

Because the validation function is just a function, we can make a higher-order function that takes the validation function and only runs it if the value is not null. Meet unlessNil:

```js
const unlessNil = R.curry((f, val) => R.or(f(val), R.isNil(val)));
```

Now we can do&nbsp;this:

```js
const optionalTypeRule = type => [
  unlessNil(isType(type)),
  (val, field) => `if ${field} is set, it must be a ${type}`
];
const validationRules = {
  appDescription: [optionalTypeRule('String')]
}
```

Of course, in order to do this, first the input object must be normalized, so all the missing fields are added with a null value. This can be done with a single function:

```js
const normalize = (spec, input) =>
  Object.keys(spec).reduce(
    (acc, x) => R.assoc(x, R.propOr(null, x, input), acc),
    {}
  );
```

Awesome, right?

Now, I’ll go into more crazy stuff, keep reading if you are interested in making a field depend on another&nbsp;one!

So, let’s say that we have a configuration field `notificationsClientId` that is only required if the boolean field `getsNotificationsis` true

A curious fact is that the validation functions in Spected, also get the whole input object as the second argument. So I knew that something like this should be possible:

```js
const validationRules = {
    notificationsClientId: [
    [
      dep("getsNotifications", R.equals(true), isType("String")),
      "If getsNotifications is true, notificationsClientId is required as a string"
    ]
  ]
}
```

As you can see, the dep function accepts three parameters:

1. the field that the current field is dependent on,
2. the function to run on said&nbsp;field,
3. and the function to run on the _current_ field if the function in the second argument returns&nbsp;`true`

dep then returns a validation function ready to be used. It may sound complicated, but look at the implementation. It’s quite&nbsp;simple:

```js
const dep = (field, cond, f) => (val, obj) =>
  cond(obj[field]) ? f(val) : true;
```

That’s it!

So, hopefully this will help you see some of the advantages of composition-friendly APIs and the functional paradigm in&nbsp;general.

Thank you for&nbsp;reading!