GraphQL
Overview

GraphQL needs both Type and Resolver to handle the request and response.

GraphQL Route

@GraphQL()
export class VersionGraphQL {}

Create

GraphQL can be created in typescript by using GraphQLSchema interface.

Both typeDefs and Query are required.

export const VersionType: GraphQLSchema = {
  typeDefs: `
        type Version {
            version: Int
            name: String
            createdAt: Int
            updatedAt: Int
        }`,
  Query: `
        versions: [Version]
        version(name:String!):[Version]
    `,
};

and use it as argument of @GraphQL like @GraphQL(VersionType)


Create GraphQL by file .graphql in graphql directory

With this way all files in the ./graphql directory will be using as type definition. all files must be end with .graphql extension.

type Version {
  version: Int
  name: String
  createdAt: Int
  updatedAt: Int
}
 
type Query {
  versions: [Version]
  version(name: String!): [Version]
}

Resolver

GraphQL Resolver is the implementation layer of type Query which is defined in the GraphQL file or object.

type VersionFilter = {
  name: string;
};
 
@GraphQL()
export class VersionGraphQL {
  private _versions = [
    {
      version: 1,
      name: "version1",
      createdAt: 223123,
      updatedAt: 55343,
    },
    {
      version: 2,
      name: "version2",
      createdAt: 223123,
      updatedAt: 55343,
    },
  ];
 
  constructor() {}
 
  @Resolver()
  async version(@Params() filter: VersionFilter, @Param("name") name: string) {
    return this._versions.filter((x) => x.name === filter.name); // name
  }
 
  @Resolver()
  async versions() {
    return this._versions;
  }
}

Secure an Endpoint

You can secure graphql api by using the @Guard.

@GraphQL()
@Guard({ roles: ["admin"] })
export class VersionGraphQL {
  constructor(private readonly _service: TodoService) {}
 
  @Resolver()
  @Guard({ roles: ["admin"], permissions: ["find-all"] })
  async versions() {
    return this._versions;
  }
 
  @Resolver()
  async version(@Params() filter: VersionFilter, @Param("name") name: string) {
    return this._versions.filter((x) => x.name === filter.name); // name
  }
}

Register GraphQL

@Module({
  graphqls: [VersionGraphQL],
})
export class AppModule {}

Supported Decorators

DecoratorDescriptionNote
@GraphQLDeclare a class as GraphQL Controllerhas one argument for GraphQL Type
@ResolverDeclare a GraphQL Resolver for a Query function.
@GuardDeclare a GuardContext for protecting the resource access

Settings

GraphQL Server is a sub server of Heron.

const main = async () => {
  const app = await HeronJS.create({ module: AppModule });
  await app.listen({
    port: 3000,
    options: {
      cors: {
        origin: "*",
        preflightContinue: false,
        methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
      },
      globalError: GlobalApiErrorInterceptor,
    },
    subServer: {
      graphql: {
        prefix: "/gpl",
        gqlDir: "./graphql",
        cors: {},
        formatError: (error) => {},
        plugins: [],
        validationRules: [],
      },
    },
  });
};
ArgumentDescriptionNote
prefixcreate global prefix for graphql
gqlDirgraphql scalar type file dirdefault is ./graphql
corsapply cors for graphql apiswill use http cors as default if this value not provided
formatErrorglobal error formatthis will change the format of error before response back to client
pluginsexpress-graphql plugin
validationRulesexpress-graphql validation rules