@marblejs/middleware-io
A data validation middleware based on awesome io-ts library authored by gcanti.

Installation

1
yarn add @marblejs/middleware-io
Copied!
Requires @marblejs/core to be installed.

Importing

1
// HTTP
2
import { requestValidator$ } from '@marblejs/middleware-io';
3
4
// Events, eg. WebSockets
5
import { eventValidator$ } from '@marblejs/middleware-io';
Copied!

Type declaration

1
requestValidator$ :: (RequestSchema, ValidatorOptions) -> Observable<HttpRequest> -> Observable<HttpRequest>
2
eventValidator$ :: (Schema, ValidatorOptions) -> Observable<Event> -> Observable<Event>
Copied!

Parameters

requestValidator$
parameter
definition
schema
Partial<RequestSchema>(see io-ts docs)
options
<optional> ValidatorOptions
eventValidator$
parameter
definition
schema
Schema (see io-ts docs)
options
<optional> ValidatorOptions
ValidatorOptions
parameter
definition
reporter
<optional> Reporter
context
<optional> string

Usage

Let's define a user schema that will be used for I/O validation.
user.schema.ts
1
export const userSchema = t.type({
2
id: t.string,
3
firstName: t.string,
4
lastName: t.string,
5
roles: t.array(t.union([
6
t.literal('ADMIN'),
7
t.literal('GUEST'),
8
])),
9
});
10
11
export type User = t.TypeOf<typeof userSchema>;
Copied!
1
import { use, r } from '@marblejs/core';
2
import { requestValidator$, t } from '@marblejs/middleware-io';
3
import { userSchema } from './user.schema.ts';
4
5
const effect$ = r.pipe(
6
r.matchPath('/'),
7
r.matchType('POST'),
8
r.useEffect(req$ => req$.pipe(
9
requestValidator$({ body: userSchema }),
10
// ..
11
)));
Copied!
For more validation use cases and recipes, visit Validation chapter.
You can also reuse the same schema for Events validation if you want.
1
import { matchEvent, act } from '@marblejs/core';
2
import { WsEffect } from '@marblejs/websockets';
3
import { eventValidator$, t } from '@marblejs/middleware-io';
4
import { userSchema } from './user.schema.ts';
5
6
const postUser$: WsEffect = event$ =>
7
event$.pipe(
8
matchEvent('CREATE_USER'),
9
act(eventValidator$(userSchema)),
10
act(event => { ... }),
11
);
Copied!
The inferred req.body / event.payload type of provided schema, will be of the following form:
1
type User = {
2
id: string;
3
firstName: string;
4
lastName: string;
5
roles: ('ADMIN' | 'GUEST')[];
6
};
Copied!
Please note that each eventValidator$ must be applied inside act operator to prevent closing of the main observable stream.

Validation errors

Lets take a look at the default reported validation error thrown by eventValidator$ . Let's assume that client passed wrong values for firstName and roles fields.
1
payload.lastName = false;
2
payload.roles = ['TEST'];
Copied!
The reported error intercepted via default error effect will look like follows.
1
{
2
type: 'CREATE_USER',
3
error: {
4
message: 'Validation error',
5
data: [
6
{
7
path: 'lastName',
8
expected: 'string',
9
got: 'false'
10
},
11
{
12
path: 'roles.0.0',
13
got: '"TEST"',
14
expected: '"ADMIN"'
15
},
16
{
17
path: 'roles.0.1',
18
got: '"TEST"',
19
expected: '"GUEST"'
20
}
21
]
22
}
23
}
Copied!

Reporters

You can create custom reporters by conforming to io-ts Reporter interface.
1
interface Reporter<A> {
2
report: (validation: Validation<any>) => A
3
}
Copied!
In order to use custom reporter you have to pass it with options object as a second argument.
1
requestValidator$(schema, { reporter: customReporter });
Copied!
Last modified 1yr ago