Skip to main content

Bridges

To make use of any schema, uniforms have to create a bridge of it - a unified schema mapper.

Currently available bridges:

  • GraphQLBridge in uniforms-bridge-graphql
  • JSONSchemaBridge in uniforms-bridge-json-schema
  • SimpleSchema2Bridge in uniforms-bridge-simple-schema-2
  • SimpleSchemaBridge in uniforms-bridge-simple-schema

If you see a lot of Warning: Unknown props... logs, check if your schema or theme doesn't provide extra props. If so, consider registering it with filterDOMProps.

GraphQLBridge#

This bridge enables using GraphQL schema types as uniforms forms. This saves you from not having to rewrite the form schema in your code. As a trade-off, you have to write the validator from scratch. In some cases, it might be easier to rewrite the schema and use, for example, JSONSchemaBridge with ajv. If only a simple or no validation is needed, this bridge is perfectly suited to work with GraphQL schemas.

The constructor accepts three arguments:

  • schema: GraphQLType can be any type parsed and extracted from a GraphQL schema.
  • validator: (model: Record<string, any>) => any a custom validator function that should return a falsy value if no errors are present or information about errors in the model as described in the custom bridge section.
  • extras: Record<string, any> = {} used to extend the schema generated from GraphQL type with extra field configuration.

Code example#

import { GraphQLBridge } from 'uniforms-bridge-graphql';
import { buildASTSchema, parse } from 'graphql';
const schema = `
type Author {
id: String!
firstName: String
lastName: String
}
type Post {
id: Int!
author: Author!
title: String
votes: Int
}
# This is required by buildASTSchema
type Query { anything: ID }
`;
const schemaType = buildASTSchema(parse(schema)).getType('Post');
const schemaExtras = {
id: {
allowedValues: [1, 2, 3]
},
title: {
options: [
{ label: 1, value: 'a' },
{ label: 2, value: 'b' }
]
},
'author.firstName': {
placeholder: 'John'
}
};
const schemaValidator = (model: object) => {
const details = [];
if (!model.id) {
details.push({ name: 'id', message: 'ID is required!' });
}
if (!model.author.id) {
details.push({ name: 'author.id', message: 'Author ID is required!' });
}
if (model.votes < 0) {
details.push({
name: 'votes',
message: 'Votes must be a non-negative number!'
});
}
// ...
return details.length ? { details } : null;
};
const bridge = new GraphQLBridge(schemaType, schemaValidator, schemaExtras);

JSONSchemaBridge#

import Ajv from 'ajv';
import { JSONSchemaBridge } from 'uniforms-bridge-json-schema';
const ajv = new Ajv({ allErrors: true, useDefaults: true });
const schema = {
title: 'Person',
type: 'object',
properties: {
firstName: { type: 'string' },
lastName: { type: 'string' },
age: {
description: 'Age in years',
type: 'integer',
minimum: 0
}
},
required: ['firstName', 'lastName']
};
function createValidator(schema: object) {
const validator = ajv.compile(schema);
return (model: object) => {
validator(model);
return validator.errors?.length ? { details: validator.errors } : null;
};
}
const schemaValidator = createValidator(schema);
const bridge = new JSONSchemaBridge(schema, schemaValidator);

Note on allOf/anyOf/oneOf#

The current handling of allOf/anyOf/oneOf is not complete and does not work with all possible cases. For an in-detail discussion, see #863. How it works, is that only a few properties are being used:

  • properties, where all subfields are merged (last definition wins),
  • required, where all properties are accumulated, and
  • type, where the first one is being used.

Below is an example of these implications:

{
"type": "object",
"properties": {
// This will render `NumField` WITHOUT `min` nor `max` properties.
// It will be properly validated, but without any UI guidelines.
"foo": {
"type": "number",
"allOf": [{ "minimum": 0 }, { "maximum": 10 }]
},
// This will render as `TextField`.
"bar": {
"oneOf": [{ "type": "string" }, { "type": "number" }]
}
}
}

SimpleSchema2Bridge#

import SimpleSchema from 'simpl-schema';
import SimpleSchema2Bridge from 'uniforms-bridge-simple-schema-2';
const PersonSchema = new SimpleSchema({
// ...
aboutMe: {
type: String,
uniforms: MyText, // Component...
uniforms: {
// ...or object...
component: MyText, // ...with component...
propA: 1 // ...and/or extra props.
}
}
});
const bridge = new SimpleSchema2Bridge(PersonSchema);

SimpleSchemaBridge#

import SimpleSchemaBridge from 'uniforms-bridge-simple-schema';
import { SimpleSchema } from 'aldeed:simple-schema';
const PersonSchema = new SimpleSchema({
// ...
aboutMe: {
type: String,
uniforms: MyText, // Component...
uniforms: {
// ...or object...
component: MyText, // ...with component...
propA: 1 // ...and/or extra props.
}
}
});
const bridge = new SimpleSchemaBridge(PersonSchema);