Skip to content

Map GraphQL directive constraints validations to typeorm entities to share and sync validation logic across multiple app layers

License

Notifications You must be signed in to change notification settings

kristianmandrup/graphql-typeorm-validation

Repository files navigation

Graphql typeorm validation

Map GraphQL type definitions @constaints directives to validations in typeorm entities. This allows you to kep validations in sync across app layers (mutations, entities) from a single source of truth (GraphQL type definitions)

Also allows decorating any type of entity model (not just typeorm) with class-validator validators, via GraphQL type definition constraints, converted to object form using graphSchemaToJson

Status

This library has not been published yet and is still a WIP. Has not even been tested. At this point just a collection of functions which might be useful and should be composable enough to fit scenarios described below.

For more on this, see this typeorm issue the objective is fully fleshed out.

TypeORM Entity validation

This library lets your wrap TypeORM @Entity classes with validation logic.

The validation constraints are extracted via graphGenTypeorm from a GraphQL type definition, defined using a @constraints directive.

graphGenTypeorm generates entity metadata used by typeorm to define the ORM for the entities. This metadata also contains all the directives applied to each field, including @constraints

The function buildEntityClassMap(connection) can load this entity metadata from a given connection, extract the constraint metadata and apply it on each class property as class-validator decorators.

In effect taking a typedef like:

type Person {
  name: String! @constraints(minLength: 2, maxLength: 60)
}

And applying it via the typeorm connection "backdoor" to achieve the following entity (along with any DB related metadata)

@Entity
class Person extends BaseEntity {
  @MinLength(2)
  @MaxLength(60)
  name: string;
}

When calling buildEntityClassMap you can pass a custom decorator function to apply custom validation logic as you see fit.

Usage

import { buildEntityClassMap } from 'graphql-typeorm-validation';

const entityClassMap = buildEntityClassMap(connection);
const { Post } = entityClassMap;
// ...
let postRepository = connection.getRepository('Post');

let post = new Post();
post.title = 'A new Post';
post.text = 'bla bla bla';
await validate(post, {
  // ... optional validation options
});
await postRepository.save(post);

This means that you can have your application generate GraphqL resolver logic to apply validation both on the input object (arguments) of a mutation and on the entity created to be saved in the DB. You can then add additional validation on the entity as you see fit. This ensures that if you access the entities in other contexts, such as via a different API (f.ex REST), the validation defined in the GraphQL type definition still applies.

No more manual sync across your entire codebase!

The default decoration of buildEntityClassMap makes async save() and async validate(opts) available as instance methods on the Entity class, so that you can simplify it to:

import { buildEntityClasses } from 'graphql-typeorm-validation';
const entityClassMap = buildEntityClassMap(connection);
const { Post } = entityClassMap;

let post = new Post();
post.title = 'A new Post';
post.text = 'bla bla bla';
const errors = await post.validate();
errors ? handleErrors(error) : await post.save();

Package generator

This project (package) was bootstrapped using typescript-starter

TypeORM Resources on entities metadata

Also see discusions on (old) issues in graphGenTypeorm

License

MIT

About

Map GraphQL directive constraints validations to typeorm entities to share and sync validation logic across multiple app layers

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published