Flow: runtime validation on demand

Aleksandr Anokhin
3 min readFeb 13, 2018

--

Problem
I tried flow just a couple of weeks ago for a new backend service and found it a pretty cool tool (if that could be named so) to keep code safe. Few words about the service: it is accessible via REST and MQ for other services, this service is generating some text messages of the type passed depending on the parameters passed. For example:

// Request body
{
type: ‘SpectatorsMessage’,
parameters: { eventId: 12345 }
}

Assume that you have a lots of message classes with different types required in constructor.

// @flow// messages.js
type Params = { eventId: number };
export class SpectatorsMessage {
constructor(params: Params) {…}
}
// many other messages

And when I was implementing logic in message generation, mapping data etc. I was very happy with flow, but when I added a simple route for generating this messages I was stuck.

import * as messages from ‘my-messages’;
router.post(‘/message’, ctx => {
const { type, parameters } = ctx.request.body;
const Message = messages[type];
if (Message) {
// and here I would like to do some validation
// of parameters for this type of message

I hope you understand that flow is a static type checker and it does not provide any runtime checks. There is a module flow-runtime for that however it is slow for production and I didn’t want to type check all the code.

Though I did not want to copy flow types and transform them to some validator functions, json-schema or other. I tried to find something acceptable for this purpose (npm module of course) but nothing.

Solution:

I decided to make my own babel plugin (probably I’d better did a codemod script) which transforms flow types to JSON schema. Now that message class would look like this:

// IN:
type Params = { eventId: number };
export class SpectatorsMessage {
// $flow-to-json
static propTypes: Params;
constructor(params: Params) {…}
}
// OUT:
export class SpectatorsMessage {
// $flow-to-json
static propTypes = {
type: 'object',
properties: { eventId: { type: 'number' } },
required: ['eventId']
};
constructor(params: Params) {…}
}

Comment $flow-to-json is used to show babel plugin that you want to transform this property to json-schema of passed type (it handles any static properties in classes).

So now I have a valid JSON schema (draft 6) and can easily validate properties I want to be checked at runtime. It covers many use cases (all of mine f.ex.), now, there are not many things left not implemented. You can check the repository, see what is implemented and not in the readme. I’d be happy for feedback if you test it, create an issue, PR or just give it a star.

P.S. Sorry, if the example in this article was not clear or strange, but in the readme of the repo you can find probably a more obvious one.

--

--