npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nestjs-graphql-errors

v1.0.4

Published

A set of utilities to build a code-first, type-safe GraphQL API with NestJS using error as data approach

Downloads

19

Readme

nestjs-graphql-errors

Description

This library provides a set of utilities to build a code-first, type-safe GraphQL API with NestJS using error as data approach. By default, NestJS uses the default GraphQL way to expose application errors to clients. This mechanism is difficult to parse, hard to differentiate, and not typed in the GraphQL schema. Because of this, it's not unusual to handle errors as data.

Install

npm install nestjs-graphql-errors

or

yarn install nestjs-graphql-errors

or

pnpm install nestjs-graphql-errors

Usage

Library uses the following concepts:

  • GraphQLExceptionFilter;
  • GraphQLError;
  • GraphQLError union;
  • GraphQLResult;
  • GraphQLException.

GraphQLExceptionFilter

Any GraphQLException is a subclass of BaseGraphQLException (or BaseGraphQLListException to deal with a list of exceptions).

To override the default NestJS way of handling exceptions, we need to provide our own ExceptionFilter. Under the hood, GraphQLExceptionFilter catches any subclass of BaseGraphQLException or BaseGraphQLListException and transforms exception data to an acceptable format.

The library exports a helper module, GraphQLErrorsModule, if it's more appropriate to just import the module with a global ExceptionFilter.

import { Module } from '@nestjs/common';
import { GraphQLErrorsModule } from 'nests-graphql-errors';

@Module({
  imports: [GraphQLErrorsModule]
})
export class SomeModule {}

The library also exports GraphQLExceptionFilter itself.

A global-scoped filter can be registered as a provider.

import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { GraphQLExceptionFilter } from 'nests-graphql-errors';

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: GraphQLExceptionFilter,
    }
  ]
})
export class SomeModule {}

Or outside of any module via useGlobalFilters.

import { NestFactory } from '@nestjs/core';
import { GraphQLExceptionFilter } from 'nestjs-graphql-errors';

import { AppModule } from './app.module';

async function bootstrap(): Promise<void> {
  const app = await NestFactory.create(AppModule);

  app.useGlobalFilters(new GraphQLExceptionFilter());

  await app.listen(3000);
}

bootstrap();

Usage of resolver-scoped filter.

import { UseFilters } from '@nestjs/common';
import { Resolver } from '@nestjs/graphql';
import { GraphQLExceptionFilter } from 'nestjs-graphql-errors';

@UseFilters(new GraphQLExceptionFilter())
@Resolver()
export class SomeResolver {}

Method-scoped filter.

import { UseFilters } from '@nestjs/common';
import { Query, Resolver } from '@nestjs/graphql';
import { GraphQLExceptionFilter } from 'nestjs-graphql-errors';

import { SomeResult } from './result/some.result.ts'

@Resolver()
export class SomeResolver {
  ...

  @UseFilters(GraphQLExceptionFilter)
  @Query(() => SomeResult, {
    name: 'some',
    nullable: false
  })
  public async some(): Promise<SomeResult> {
    ...
  }

  ...
}

GraphQLError

GraphQLError is a special ObjectType that implements BaseGraphQLError interface.

Every GraphQLError has two default fields:

  • message. A nullable string field that describes the error;
  • code. A non-nullable field, either a string or an enum, serving as the error descriptor.

When a custom GraphQLError extends GraphQLError without arguments, the code type defaults to string.

import { ObjectType } from '@nestjs/graphql';
import { GraphQLError } from 'nestjs-graphql-errors';

@ObjectType('SomeError')
export class SomeError extends GraphQLError() {}

GraphQLError can be called with an enum argument. In such cases, the same enum will be used as the field type.

import { ObjectType } from '@nestjs/graphql';
import { GraphQLError } from 'nestjs-graphql-errors';

export enum SomeErrorCode {
  ANOTHER_ERROR_CODE,
  SOME_ERROR_CODE,
}

@ObjectType('SomeError')
export class SomeError extends GraphQLError(SomeErrorCode) {}

Do not forget to register the enum.

...

import { registerEnumType } from '@nestjs/graphql';

import { SomeErrorCode } from '...';

...

registerEnumType(SomeErrorCode, { name: 'SomeErrorCode' });

...

Any additional fields defined in a custom GraphQLError will be used as extra fields for a corresponding GraphQLException.

import { Field, ID, ObjectType } from '@nestjs/graphql';
import { GraphQLError } from 'nestjs-graphql-errors';

@ObjectType('SomeError')
export class SomeError extends GraphQLError() {
  @Field(() => ID, {
    name: 'someId',
    nullable: false
  })
  public readonly someId: string;
}

GraphQLError union

Sometimes GraphQLResult is expected to have single error of a union type. Define such unions with a help of graphqlErrorUnionFactory.

import { graphqlErrorUnionFactory } from 'nestjs-graphql-errors';

import { AnotherError } from './another.error.ts';
import { SomeError } from './some.error.ts';

export const UnionError = graphqlErrorUnionFactory('UnionError', [AnotherError, SomeError]);

GraphQLResult

GraphQLExceptionFilter expects the response type to have the following definition when any GraphQLException is caught:

...

type OperationResult {
  data: OperationDto
  error: OperationError
}

...

The library provides a base GraphQLResult type to avoid boilerplate code.

GraphQLResult requires data and error class references.

import { ObjectType } from '@nestjs/graphql';
import { GraphQLResult } from 'nestjs-graphql-errors';

import { SomeDto } from '../dto/some.dto.ts';
import { UnionError } from '../error/union.error.ts';

@ObjectType('SomeResult')
export class SomeResult extends GraphQLResult(SomeDto, UnionError);

They can reference an array as well.

import { ObjectType } from '@nestjs/graphql';
import { GraphQLResult } from 'nestjs-graphql-errors';

import { SomeDto } from '../dto/some.dto.ts';
import { UnionError } from '../error/union.error.ts';

@ObjectType('SomeResult')
export class SomeResult extends GraphQLResult([SomeDto], [UnionError]);

GraphQLException

GraphQLException is created based on the GraphQLError reference. It allows us to infer the code field type and any extra fields.

import { graphqlExceptionFactory } from 'nestjs-graphql-errors';

import { SomeError } from '../../presentation/error';

export const SomeException = graphqlExceptionFactory(SomeError);

GraphQLException without extra fields.

...

import { SomeException } from '../core/exceptions';

...

throw new SomeException('SOME_ERROR_CODE', 'Some error message');

...

GraphQLException with extra fields (required argument).

...

import { SomeException } from '../core/exceptions';

...

throw new SomeException('SOME_ERROR_CODE', 'Some error message', { someId: 'id' });

...

GraphQLException with an enum value as a code (inferred type).

...

import { SomeException } from '../core/exceptions';

import { SomeErrorCode } from '../presentation/error';

...

throw new SomeException(SomeErrorCode.SOME_ERROR_CODE, 'Some error message');

...

BaseGraphQLListException is intended to be used in cases where a GraphQL operation may return multiple errors.

Exception constructor accepts variable length arguments.

...

import { BaseGraphQLListException } from 'nestjs-graphql-errors';

import { SomeException } from '../core/exceptions';

...

throw new BaseGraphQLListException(
  new SomeException('SOME_ERROR_CODE', 'Some error message'),
  new SomeException('SOME_ERROR_CODE', 'Some error message'),
  new SomeException('SOME_ERROR_CODE', 'Some error message'),
);

...

Resulting schema

Example of resulting GraphQL schema.

type Query {
  some(input: SomeInput!): SomeResult!
}

type SomeDto {
  id: ID!
}

interface BaseGraphQLError {
  message: String
}

enum SomeErrorCode {
  ANOTHER_ERROR_CODE
  SOME_ERROR_CODE
}

type AnotherError implements BaseGraphQLError {
  message: String
  code: String!
}

type SomeError implements BaseGraphQLError {
  message: String
  code: SomeErrorCode!
  someId: ID!
}

union UnionError = AnotherError | SomeError

type SomeResult {
  data: SomeDto
  error: UnionError
}
query ($input: SomeInput!) {
  some(input: $input) {
    data {
      id
    }
    error {
      ... on AnotherError {
        anotherErrorCode: code
        message
      }
      ... on SomeError {
        someErrorCode: code
        message
        someId
      }
    }
  }
}