TypeGraphQL

repository·master·Indexed 27 days ago

https://github.com/michallytek/type-graphql

A library for creating GraphQL schemas and resolvers using TypeScript classes and decorators. It eliminates redundancy between SDL, TypeScript interfaces, and ORM models. Version 2.0.0-rc.4 supports defining object types with @ObjectType, creating resolvers with @Resolver, and implementing authorization guards via @Authorized. It provides integration guides for Apollo Server, AWS Lambda, and Microsoft Azure Functions.

Tokens
32.3K
Snippets
102
Records
150
Agent score
93%

What's inside type-graphql

  1. Explore TypeGraphQL feature examples

    master

    The repository contains categorized examples demonstrating various TypeGraphQL capabilities:

    Basics

    • Simple usage of fields, basic types, and resolvers

    Advanced

    • Enums and unions
    • Subscriptions (simple and Redis-based)
    • Interfaces and inheritance
    • Metadata extensions

    Feature Usage

    • Dependency injection (IoC containers and scoped containers)
    • Authorization
    • Validation (automatic and custom)
    • Types, Resolvers, and Generic types inheritance
    • Mixin classes
    • Middlewares and Custom Decorators
    • Query complexity

    3rd Party Library Integrations

    • ORMs: TypeORM (manual/synchronous and automatic/lazy relations), MikroORM, Typegoose
    • Apollo Ecosystem: Apollo Federation (v1 and v2), Apollo Cache Control
    • Other: GraphQL Scalars, TSyringe
  2. Configure PubSub in buildSchema for v2.0

    master

    In v2.0, passing a PubSub instance to the buildSchema configuration is now required. Previously, TypeGraphQL provided a default instance.

    While you can use any system that implements the PubSub interface (requiring .subscribe() and .publish() methods), it is recommended to use @graphql-yoga/subscriptions to take advantage of type-safe topics via createPubSub.

    import { buildSchema } from "type-graphql";
    import { createPubSub } from "@graphql-yoga/subscriptions";
    
    export const pubSub = createPubSub<{
      NOTIFICATIONS: [NotificationPayload];
      DYNAMIC_ID_TOPIC: [number, NotificationPayload];
    }>();
    
    const schema = await buildSchema({
      resolver,
      pubSub,
    });
  3. Organize Azure Function project structure

    master

    For better maintainability, separate your Azure Function handlers from your core GraphQL resolvers and services. Place handlers in a dedicated /handlers directory.

    /YOUR_PROJECT
      /handlers
        /handler-graphql
          index.ts
          function.json
        /handler-SOME-OTHER-FUNCTION-1
          index.ts
          function.json
    
      /src
        /resolvers
          user.resolver.ts
          account.resolver.ts
        /services
          user.service.ts
    
      package.json
      host.json
  4. Register the authChecker in buildSchema

    master

    After defining your authorization logic, you must register the authChecker when building your GraphQL schema using buildSchema.

    import { buildSchema } from "type-graphql";
    import { customAuthChecker } from "../auth/custom-auth-checker.ts";
    
    const schema = await buildSchema({
      resolvers: [MyResolver],
      authChecker: customAuthChecker,
    });
  5. Create GraphQL Resolvers with Queries, Mutations, and Field Resolvers

    master

    Resolvers are controller-like classes annotated with the @Resolver() decorator.

    • Use @Query(returns => Type) to define queries.
    • Use @Mutation() to define mutations.
    • Use @FieldResolver() to define resolvers for specific fields on an object type. Use the @Root() decorator to access the parent object (the root) of the field being resolved.
    • Use @Arg("name") to define arguments for queries or mutations.
    • Use @Authorized(Roles) as an auth guard to restrict access.
    • Supports dependency injection via the class constructor.
    @Resolver(Recipe)
    class RecipeResolver {
      // dependency injection
      constructor(private recipeService: RecipeService) {}
    
      @Query(returns => [Recipe])
      recipes() {
        return this.recipeService.findAll();
      }
    
      @Mutation()
      @Authorized(Roles.Admin) // auth guard
      removeRecipe(@Arg("id") id: string): boolean {
        return this.recipeService.removeById(id);
      }
    
      @FieldResolver()
      averageRating(@Root() recipe: Recipe) {
        return recipe.ratings.reduce((a, b) => a + b, 0) / recipe.ratings.length;
      }
    }
  6. Handle Complex Generic Type Values (Scalars and Primitives)

    master

    If you need to use something other than a class (like a GraphQLScalarType or a primitive like String) as a generic field type, you must update the factory function's parameter signature to accept these types. This allows you to pass runtime values like String or Number into the @Field decorator.

    export default function PaginatedResponse<TItemsFieldValue extends object>(
      itemsFieldValue: ClassType<TItemsFieldValue> | GraphQLScalarType | String | Number | Boolean,
    ) {
      @ObjectType()
      abstract class PaginatedResponseClass {
        @Field(type => [itemsFieldValue])
        items: TItemsFieldValue[];
    
        // ... Other fields
      }
      return PaginatedResponseClass;
    }
    
    // Usage for a response containing an array of strings
    @ObjectType()
    class PaginatedStringsResponse extends PaginatedResponse<string>(String) {
      // ...
    }
  7. Integrate TypeGraphQL with NestJS

    master

    You can use TypeGraphQL features within the NestJS module system and dependency injector by using the typegraphql-nestjs package.

    1. Register Resolvers: Add your TypeGraphQL resolver classes to the providers array of your NestJS @Module.
    2. Configure TypeGraphQLModule: Register the TypeGraphQLModule in your root module using .forRoot(). You can pass standard buildSchema options such as emitSchemaFile, authChecker, and context to this method.
    // 1. Register resolvers in a feature module
    @Module({
      providers: [RecipeResolver, RecipeService],
    })
    export default class RecipeModule {}
    
    // 2. Register TypeGraphQLModule in the root module
    @Module({
      imports: [
        TypeGraphQLModule.forRoot({
          emitSchemaFile: true,
          authChecker,
          context: ({ req }) => ({ currentUser: req.user }),
        }),
        RecipeModule,
      ],
    })
    export default class AppModule {}
  8. Hide properties from the GraphQL schema

    master

    To prevent a class property from being exposed in the GraphQL schema, simply omit the @Field() decorator. This is useful for properties that are needed for internal logic or database storage but should not be publicly accessible via the API.

    @ObjectType()
    class Rate {
      @Field(type => Int)
      value: number;
    
      @Field()
      date: Date;
    
      // This property is stored in the DB but hidden from GraphQL
      user: User;
    }
  9. Use TypeGraphQL classes in Create React App (CRA) or Webpack-based apps

    master

    Because TypeGraphQL is a Node.js framework, attempting to use its decorated classes (e.g., for class-validator or custom methods) in a browser environment will cause build errors like ERROR in ./node_modules/fs.realpath/index.js.

    To fix this, use a NormalModuleReplacementPlugin in your Webpack configuration to redirect imports from type-graphql to the type-graphql/shim. This prevents the full library from being bundled, resulting in a lighter client bundle.

    module.exports = {
      // ... Rest of Webpack configuration
      plugins: [
        // ... Other existing plugins
        new webpack.NormalModuleReplacementPlugin(/type-graphql$/, resource => {
          resource.request = resource.request.replace(/type-graphql/, "type-graphql/shim");
        }),
      ];
    }
  10. Emit the schema SDL automatically during buildSchema

    master

    You can automatically generate a schema.graphql file when calling buildSchema. This is useful for providing SDL files to client-side tools for autocompletion and validation, or for schema regression snapshots.

    There are three ways to configure this via the buildSchema options:

    1. Enable default emission: Set emitSchemaFile: true to create schema.graphql in the project's root working directory.
    2. Specify a custom path: Provide a string representing the absolute path and filename.
    3. Use a configuration object: Pass an object to specify the path and sortedSchema (boolean) settings. By default, the schema is sorted alphabetically.
    const schema = await buildSchema({
      resolvers: [ExampleResolver],
      // Automatically create `schema.graphql` file with schema definition in project's working directory
      emitSchemaFile: true,
      // Or create the file with schema in selected path
      emitSchemaFile: path.resolve(__dirname, "__snapshots__/schema/schema.graphql"),
      // Or pass a config object
      emitSchemaFile: {
        path: __dirname + "/schema.graphql",
        sortedSchema: false, // By default the printed schema is sorted alphabetically
      },
    });