Skip to content

Commit

Permalink
feat(validation): make class-validator a peer dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
MichalLytek committed Mar 28, 2020
1 parent 9476cba commit fe61e9b
Show file tree
Hide file tree
Showing 11 changed files with 44 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- **Breaking Change**: update `graphql-js` peer dependency to `^14.6.0`
- **Breaking Change**: update `graphql-query-complexity` dependency to `^0.4.1` and drop support for `fieldConfigEstimator` (use `fieldExtensionsEstimator` instead)
- **Breaking Change**: introduce `sortedSchema` option in `PrintSchemaOptions` and emit sorted schema file by default
- **Breaking Change**: make `class-validator` an optional, peer dependency (#366)
- update `TypeResolver` interface to match with `GraphQLTypeResolver` from `graphql-js`
- add basic support for directives with `@Directive()` decorator (#369)
- add possibility to tune up the performance and disable auth & middlewares stack for simple field resolvers (#479)
Expand Down
4 changes: 2 additions & 2 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ Before getting started with TypeGraphQL we need to install some additional depen
## Packages installation

First, we have to install the main package, as well as [`graphql-js`](https://github.com/graphql/graphql-js) which is a peer dependency of TypeGraphQL:
First, we have to install the main package, as well as [`graphql-js`](https://github.com/graphql/graphql-js) and [`class-validator`](https://github.com/typestack/class-validator) which are peer dependencies of TypeGraphQL:

```sh
npm i graphql type-graphql
npm i graphql class-validator type-graphql
```

Also, the `reflect-metadata` shim is required to make the type reflection work:
Expand Down
14 changes: 10 additions & 4 deletions docs/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ And that's it! 😉
TypeGraphQL will automatically validate our inputs and arguments based on the definitions:

```typescript
@Resolver(of => Recipe)
@Resolver((of) => Recipe)
export class RecipeResolver {
@Mutation(returns => Recipe)
@Mutation((returns) => Recipe)
async addRecipe(@Arg("input") recipeInput: RecipeInput): Promise<Recipe> {
// you can be 100% sure that the input is correct
console.assert(recipeInput.title.length <= 30);
Expand All @@ -73,7 +73,7 @@ And we can still enable it per resolver's argument if we need to:

```typescript
class RecipeResolver {
@Mutation(returns => Recipe)
@Mutation((returns) => Recipe)
async addRecipe(@Arg("input", { validate: true }) recipeInput: RecipeInput) {
// ...
}
Expand All @@ -84,7 +84,7 @@ The `ValidatorOptions` object used for setting features like [validation groups]

```typescript
class RecipeResolver {
@Mutation(returns => Recipe)
@Mutation((returns) => Recipe)
async addRecipe(
@Arg("input", { validate: { groups: ["admin"] } })
recipeInput: RecipeInput,
Expand Down Expand Up @@ -167,6 +167,12 @@ By default, the `apollo-server` package from the [bootstrap guide](bootstrap.md)

Of course we can also create our own custom implementation of the `formatError` function provided in the `ApolloServer` config options which will transform the `GraphQLError` with a `ValidationError` array in the desired output format (e.g. `extensions.code = "ARGUMENT_VALIDATION_ERROR"`).

## Caveats

Even if we don't use the validation feature (and we have provided `{ validate: false }` option to `buildSchema`), we still need to have `class-validator` installed as a dev dependency in order to compile our app without errors using `tsc`.

An alternative solution that allows to completely get rid off big `class-validator` from our project's `node_modules` folder is to suppress the `error TS2307: Cannot find module 'class-validator'` TS error by providing `"skipLibCheck": true` setting in `tsconfig.json`.

## Example

To see how this works, check out the [simple real life example](https://github.com/MichalLytek/type-graphql/tree/master/examples/automatic-validation).
30 changes: 20 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
"postinstall": "node ./dist/postinstall || exit 0"
},
"peerDependencies": {
"graphql": "^14.6.0"
"graphql": "^14.6.0",
"class-validator": ">=0.9.1"
},
"dependencies": {
"@types/glob": "^7.1.1",
"@types/node": "*",
"@types/semver": "^7.1.0",
"class-validator": ">=0.9.1",
"glob": "^7.1.6",
"graphql-query-complexity": "^0.4.1",
"graphql-subscriptions": "^1.1.0",
Expand All @@ -48,6 +48,7 @@
"apollo-server": "^2.11.0",
"apollo-server-express": "^2.11.0",
"class-transformer": "^0.2.3",
"class-validator": "^0.12.0-rc.0",
"del": "^5.1.0",
"express": "^4.17.1",
"graphql": "^14.6.0",
Expand Down
2 changes: 1 addition & 1 deletion src/decorators/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GraphQLScalarType } from "graphql";
import { ValidatorOptions } from "class-validator";
import type { ValidatorOptions } from "class-validator";

import {
ResolverFilterData,
Expand Down
2 changes: 1 addition & 1 deletion src/errors/ArgumentValidationError.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ValidationError } from "class-validator";
import type { ValidationError } from "class-validator";

export class ArgumentValidationError extends Error {
constructor(public validationErrors: ValidationError[]) {
Expand Down
2 changes: 1 addition & 1 deletion src/metadata/definitions/param-metadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ValidatorOptions } from "class-validator";
import type { ValidatorOptions } from "class-validator";

import { TypeValueThunk, TypeOptions } from "../../decorators/types";
import { ResolverData } from "../../interfaces";
Expand Down
4 changes: 2 additions & 2 deletions src/resolvers/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PubSubEngine } from "graphql-subscriptions";
import { ValidatorOptions } from "class-validator";
import type { ValidatorOptions } from "class-validator";

import { ParamMetadata } from "../metadata/definitions";
import { convertToType } from "../helpers/types";
Expand All @@ -19,7 +19,7 @@ export function getParams(
): Promise<any[]> | any[] {
const paramValues = params
.sort((a, b) => a.index - b.index)
.map(paramInfo => {
.map((paramInfo) => {
switch (paramInfo.kind) {
case "args":
return validateArg(
Expand Down
4 changes: 2 additions & 2 deletions src/resolvers/validate-arg.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ValidatorOptions } from "class-validator";
import type { ValidatorOptions } from "class-validator";

import { ArgumentValidationError } from "../errors/ArgumentValidationError";

Expand All @@ -24,7 +24,7 @@ export async function validateArg<T extends Object>(
const { validateOrReject } = await import("class-validator");
try {
if (Array.isArray(arg)) {
await Promise.all(arg.map(argItem => validateOrReject(argItem, validatorOptions)));
await Promise.all(arg.map((argItem) => validateOrReject(argItem, validatorOptions)));
} else {
await validateOrReject(arg, validatorOptions);
}
Expand Down
2 changes: 1 addition & 1 deletion src/schema/build-context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GraphQLScalarType } from "graphql";
import { ValidatorOptions } from "class-validator";
import type { ValidatorOptions } from "class-validator";
import { PubSubEngine, PubSub, PubSubOptions } from "graphql-subscriptions";

import { AuthChecker, AuthMode } from "../interfaces";
Expand Down

0 comments on commit fe61e9b

Please sign in to comment.