### Bootstrap Async Function Source: https://github.com/michallytek/type-graphql/blob/master/docs/bootstrap.md Wrap schema building and server setup in an async function to properly handle promises with `await`. Remember to call the bootstrap function to start the application. ```typescript import { buildSchema } from "type-graphql"; async function bootstrap() { const schema = await buildSchema({ resolvers: [ // ... Resolvers classes ], }); // ... } bootstrap(); // Actually run the async function ``` -------------------------------- ### Example GraphQL Query Source: https://github.com/michallytek/type-graphql/blob/master/docs/prisma.md An example of a complex GraphQL query that interacts with the database via Prisma resolvers. ```graphql query GetSomeUsers { users(where: { email: { contains: "prisma" } }, orderBy: { name: desc }) { id name email posts(take: 10, orderBy: { updatedAt: desc }) { published title content } } } ``` -------------------------------- ### GraphQL Directive Example Source: https://github.com/michallytek/type-graphql/blob/master/website/blog/2020-08-19-devto-article.md Example of defining a GraphQL schema with a directive for authorization. ```graphql type Query { foobar: String! @auth(requires: USER) } ``` -------------------------------- ### Recipe Resolver Example Source: https://github.com/michallytek/type-graphql/blob/master/docs/resolvers.md This example demonstrates how to create a resolver class with a query to fetch a collection of recipes. It uses the @Resolver() decorator for the class and the @Query() decorator for the method, specifying the return type. ```APIDOC ## Query recipes ### Description Fetches a collection of all recipes. ### Method GraphQL Query ### Endpoint N/A (GraphQL Schema Definition) ### Parameters None ### Request Example ```graphql query { recipes } ``` ### Response #### Success Response - **recipes** ([Recipe]) - An array of Recipe objects. #### Response Example ```json [ { "id": "1", "title": "Recipe Title", "description": "Recipe Description", "creationDate": "2023-10-27T10:00:00.000Z", "ingredients": [ "Ingredient 1", "Ingredient 2" ], "author": { "id": "user-1", "name": "John Doe" } } ] ``` ``` -------------------------------- ### Install Reflect Metadata Shim Source: https://github.com/michallytek/type-graphql/blob/master/docs/installation.md Install the reflect-metadata shim or core-js to enable type reflection, which is required for TypeGraphQL. ```sh npm install reflect-metadata ``` ```sh npm install core-js ``` -------------------------------- ### Install TypeGraphQL and Peer Dependencies Source: https://github.com/michallytek/type-graphql/blob/master/docs/installation.md Install the main TypeGraphQL package along with its peer dependencies, graphql-js and graphql-scalars, using npm. ```sh npm install graphql graphql-scalars type-graphql ``` -------------------------------- ### Install class-validator Source: https://github.com/michallytek/type-graphql/blob/master/docs/validation.md Install the class-validator package using npm. ```sh npm install class-validator ``` -------------------------------- ### Minimal tsconfig.json Example Source: https://github.com/michallytek/type-graphql/blob/master/docs/installation.md A minimal tsconfig.json configuration including target, module, experimental decorators, and emit decorator metadata options. ```json { "compilerOptions": { "target": "es2021", "module": "commonjs", "experimentalDecorators": true, "emitDecoratorMetadata": true } } ``` -------------------------------- ### GraphQL Schema Directive Example Source: https://github.com/michallytek/type-graphql/blob/master/docs/directives.md Illustrates how directives are declared in GraphQL schema definition language (SDL). ```graphql type Foo @auth(requires: USER) { field: String! } type Bar { field: String! @auth(requires: USER) } ``` -------------------------------- ### Basic RecipeInput without validation Source: https://github.com/michallytek/type-graphql/blob/master/website/versioned_docs/version-2.0.0-rc.4/validation.md An example of a basic RecipeInput class before applying validation decorators. ```ts @InputType() export class RecipeInput { @Field() title: string; @Field({ nullable: true }) description?: string; } ``` -------------------------------- ### GraphQL Query Example for Union Type Source: https://github.com/michallytek/type-graphql/blob/master/docs/unions.md An example GraphQL query demonstrating how to fetch fields from different types within a union. Uses inline fragments (`... on TypeName`) to specify which type's fields to retrieve. ```graphql query { search(phrase: "Holmes") { ... on Actor { # Maybe Katie Holmes? name age } ... on Movie { # For sure Sherlock Holmes! name rating } } } ``` -------------------------------- ### GraphQL Schema Output with Enum Details Source: https://github.com/michallytek/type-graphql/blob/master/docs/enums.md Example of how the GraphQL schema will look with descriptions and deprecation reasons for enum values. ```graphql enum Direction { UP DOWN LEFT """ The other left """ RIGHT SIDEWAYS @deprecated(reason: "Replaced with Left or Right") } ``` -------------------------------- ### Nested Input Type Transformation Example Source: https://github.com/michallytek/type-graphql/blob/master/website/blog/2020-08-19-devto-article.md Demonstrates how nested input types are now properly instantiated as class instances, enabling features like validation. ```typescript @InputType() class SampleInput { @Field() sampleStringField: string; @Field() nestedField: SomeNestedInput; } @Resolver() class SampleResolver { @Query() sampleQuery(@Arg("input") input: SampleInput): boolean { return input.nestedField instanceof SomeNestedInput; } } ``` -------------------------------- ### GraphQL SDL for Interface Inheritance Source: https://github.com/michallytek/type-graphql/blob/master/docs/interfaces.md Example of the resulting GraphQL Schema Definition Language (SDL) when using interface inheritance and object types implementing interfaces. ```graphql interface Node { id: ID! } interface Person implements Node { id: ID! name: String! age: Int! } type Student implements Node & Person { id: ID! name: String! age: Int! universityName: String! } ``` -------------------------------- ### Define GraphQL Resolver with Queries and Mutations Source: https://github.com/michallytek/type-graphql/blob/master/README.md Example of a 'RecipeResolver' class that handles GraphQL queries and mutations. It demonstrates dependency injection and authorization guards. ```typescript import { Resolver, Query, Mutation, Arg, Root, FieldResolver, Authorized } from "type-graphql"; @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; } } ``` -------------------------------- ### Example Resolver with Common Tasks Source: https://github.com/michallytek/type-graphql/blob/master/README.md This resolver demonstrates common tasks like repository access, authentication, validation, and business logic implementation in a typical GraphQL API. It shows how TypeGraphQL aims to streamline these processes. ```typescript export const getRecipesResolver: GraphQLFieldResolver = async ( _, args, ctx, ) => { // common tasks repeatable for almost every resolver const repository = TypeORM.getRepository(Recipe); const auth = Container.get(AuthService); await joi.validate(getRecipesSchema, args); if (!auth.check(ctx.user)) { throw new NotAuthorizedError(); } // our business logic, e.g.: return repository.find({ skip: args.offset, take: args.limit }); }; ``` -------------------------------- ### Interface Field Type Mismatch Error Message Example Source: https://github.com/michallytek/type-graphql/blob/master/website/blog/2020-08-19-devto-article.md Example of a detailed error message highlighting a type mismatch between an interface field and its implementation. ```text Some errors occurred while generating GraphQL schema: Interface field 'IUser.accountBalance' expects type 'String!' but 'Student.accountBalance' is of type 'Float' ``` -------------------------------- ### Create an Advanced Fields Parameter Decorator Source: https://github.com/michallytek/type-graphql/blob/master/docs/custom-decorators.md This example demonstrates creating an advanced parameter decorator that calculates a fields map based on GraphQL info. It can encapsulate complex logic and perform asynchronous operations, offering granular control over execution. ```typescript function Fields(level = 1): ParameterDecorator { return createParameterDecorator(async ({ info }) => { const fieldsMap: FieldsMap = {}; // Calculate an object with info about requested fields // based on GraphQL 'info' parameter of the resolver and the level parameter // or even call some async service, as it can be a regular async function and we can just 'await' return fieldsMap; }); } ``` -------------------------------- ### Build Schema with TypeDI Container Source: https://github.com/michallytek/type-graphql/blob/master/docs/dependency-injection.md Integrate TypeDI as the IoC container when building the TypeGraphQL schema. Ensure TypeDI is installed and configured. ```typescript import { buildSchema } from "type-graphql"; // IOC container import { Container } from "typedi"; import { SampleResolver } from "./resolvers"; // Build TypeGraphQL executable schema const schema = await buildSchema({ // Array of resolvers resolvers: [SampleResolver], // Registry 3rd party IOC container container: Container, }); ``` -------------------------------- ### Create Type-Safe PubSub Instance with GraphQL Yoga Source: https://github.com/michallytek/type-graphql/blob/master/docs/migration-guide.md Example of creating a type-safe PubSub instance using `@graphql-yoga/subscriptions` for TypeGraphQL v2.0 subscriptions. This instance must be passed to `buildSchema`. ```typescript 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, }); ``` -------------------------------- ### InversifyJS Self-Binding Example Source: https://github.com/michallytek/type-graphql/blob/master/docs/dependency-injection.md When using InversifyJS, concrete types must be self-bound. This example shows how to bind a resolver class to itself. ```typescript container.bind(SampleResolver).to(SampleResolver).inSingletonScope(); ``` -------------------------------- ### Create HTTP GraphQL Endpoint with Apollo Server Source: https://github.com/michallytek/type-graphql/blob/master/docs/bootstrap.md Use `@apollo/server` to create an HTTP GraphQL endpoint. Install the package separately as it's not bundled with TypeGraphQL. ```typescript import { ApolloServer } from "@apollo/server"; import { startStandaloneServer } from "@apollo/server/standalone"; const PORT = process.env.PORT || 4000; async function bootstrap() { // ... Build GraphQL schema // Create GraphQL server const server = new ApolloServer({ schema }); // Start server const { url } = await startStandaloneServer(server, { listen: { port: 4000 } }); console.log(`GraphQL server ready at ${url}`); } bootstrap(); ``` -------------------------------- ### Resolver Implementation with TypeGraphQL Source: https://github.com/michallytek/type-graphql/blob/master/docs/introduction.md Example of a GraphQL field resolver function. It demonstrates common tasks like authentication, validation, and data retrieval using TypeORM. ```typescript export const getRecipesResolver: GraphQLFieldResolver = async ( _, args, ctx, ) => { // Common tasks repeatable for almost every resolver const auth = Container.get(AuthService); if (!auth.check(ctx.user)) { throw new NotAuthorizedError(); } await joi.validate(getRecipesSchema, args); const repository = TypeORM.getRepository(Recipe); // Business logic, e.g.: return repository.find({ skip: args.offset, take: args.limit }); }; ``` -------------------------------- ### Improved Schema Generation Error Message Example Source: https://github.com/michallytek/type-graphql/blob/master/website/blog/2020-08-19-devto-article.md Example of a detailed error message indicating an issue with type inference for an input argument. ```text Unable to infer GraphQL type from TypeScript reflection system. You need to provide explicit type for argument named 'filter' of 'getUsers' of 'UserResolver' class. ``` -------------------------------- ### Accessing Extensions Data in Middleware Source: https://github.com/michallytek/type-graphql/blob/master/docs/extensions.md A middleware example demonstrating how to access and utilize extension data ('logMessage') from the GraphQLResolveInfo object during field resolution. ```typescript export class LoggerMiddleware implements MiddlewareInterface { constructor(private readonly logger: Logger) {} use({ info }: ResolverData, next: NextFn) { // extract `extensions` object from GraphQLResolveInfo object to get the `logMessage` value const { logMessage } = info.parentType.getFields()[info.fieldName].extensions || {}; if (logMessage) { this.logger.log(logMessage); } return next(); } } ``` -------------------------------- ### Defining Recipe Input with Validation Source: https://github.com/michallytek/type-graphql/blob/master/website/pages/snippets/validation.md Example of creating an InputType with validation decorators for fields like title, description, and ingredients. Use MaxLength for string length limits, Length for range, and MaxArraySize for array size limits. ```typescript import { InputType, Field } from "type-graphql"; import { MaxLength, Length, MaxArraySize } from "class-validator"; @InputType() export class RecipeInput { @Field() @MaxLength(30) title: string; @Field({ nullable: true }) @Length(30, 255) description?: string; @Field(type => [String]) @MaxArraySize(25) ingredients: string[]; } ``` -------------------------------- ### Create a Custom Parameter Decorator with Arg Metadata Source: https://github.com/michallytek/type-graphql/blob/master/docs/custom-decorators.md This example shows how to create a custom parameter decorator that also registers an argument in the GraphQL schema. It uses the `arg` key in `CustomParameterOptions` to provide metadata for `@Arg`. ```typescript function RandomIdArg(argName = "id") { return createParameterDecorator( // here we do the logic of getting provided argument or generating a random one ({ args }) => args[argName] ?? Math.round(Math.random() * MAX_ID_VALUE), { // here we provide the metadata to register the parameter as a GraphQL argument arg: { name: argName, typeFunc: () => Int, options: { nullable: true, description: "Accepts provided id or generates a random one.", }, }, }, ); } ``` -------------------------------- ### Define a Recipe object type with descriptions and nullable fields Source: https://github.com/michallytek/type-graphql/blob/master/docs/types-and-fields.md This example shows a complete Recipe object type definition with descriptions for fields and the 'id' type explicitly set to ID. The 'averageRating' field is marked as nullable. ```typescript @ObjectType({ description: "The recipe model" }) class Recipe { @Field(type => ID) id: string; @Field({ description: "The title of the recipe" }) title: string; @Field(type => [Rate]) ratings: Rate[]; @Field({ nullable: true }) averageRating?: number; } ``` -------------------------------- ### Custom Subscription Logic with Prisma Source: https://github.com/michallytek/type-graphql/blob/master/docs/subscriptions.md Implement custom subscription logic using the 'subscribe' option, for example, integrating with Prisma's subscription functionality. This option replaces 'topics' and 'filter'. ```typescript class SampleResolver { // ... @Subscription({ subscribe: ({ root, args, context, info }) => { return context.prisma.$subscribe.users({ mutation_in: [args.mutationType] }); }, }) newNotification(): Notification { // ... } } ``` -------------------------------- ### Define an Object Type with Fields Source: https://github.com/michallytek/type-graphql/blob/master/docs/introduction.md Example of defining a 'Recipe' object type using TypeGraphQL decorators. Fields can be simple types or arrays, and can be marked as nullable. ```typescript @ObjectType() class Recipe { @Field() title: string; @Field(type => [Rate]) ratings: Rate[]; @Field({ nullable: true }) averageRating?: number; } ``` -------------------------------- ### Example Resolver Function Source: https://github.com/michallytek/type-graphql/blob/master/website/blog/2018-03-25-medium-article.md A typical resolver function signature in a GraphQL API, demonstrating argument types and return values. This is the kind of code TypeGraphQL aims to simplify. ```typescript export const recipesResolver: GraphQLFieldResolver = async ( _, args, ) => { // stuffs like validation, auth checking, getting from container // and our business logic, e.g.: const repository = getRepository(Recipe); return repository.find(); }; ``` -------------------------------- ### Resolver Class with Data Storage Source: https://github.com/michallytek/type-graphql/blob/master/docs/resolvers.md A resolver class can store data or inject dependencies. This example shows a private collection to hold recipes. ```typescript import { Resolver } from "type-graphql"; @Resolver() class RecipeResolver { private recipesCollection: Recipe[] = []; } ``` -------------------------------- ### Webpack Configuration for TypeGraphQL Shim Source: https://github.com/michallytek/type-graphql/blob/master/docs/browser-usage.md Configure Webpack to replace the 'type-graphql' module with its browser shim. This is useful for Create React App (CRA) and similar setups. ```javascript 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"); }), ] } ``` -------------------------------- ### Implement Base Resolver Methods with Named Queries Source: https://github.com/michallytek/type-graphql/blob/master/website/versioned_docs/version-2.0.0-rc.4/inheritance.md Implement resolver methods within the base class, using the `name` option in decorators like `@Query` to define schema-specific names. This example adds a `getAll` query. ```typescript import { ClassType, Resolver, Query, Arg, Int } from "type-graphql"; function createBaseResolver(suffix: string, objectTypeCls: T) { @Resolver() abstract class BaseResolver { protected items: T[] = []; @Query(type => [objectTypeCls], { name: `getAll${suffix}` }) async getAll(@Arg("first", type => Int) first: number): Promise { return this.items.slice(0, first); } } return BaseResolver; } ``` -------------------------------- ### Integrate graphql-query-complexity with Apollo Server Source: https://github.com/michallytek/type-graphql/blob/master/docs/complexity.md Implement a plugin for Apollo Server to analyze query complexity on each request. This example uses fieldExtensionsEstimator and simpleEstimator to calculate complexity and throws an error if it exceeds a defined maximum. ```typescript import { ApolloServer } from "@apollo/server"; import { startStandaloneServer } from "@apollo/server/standalone"; import { getComplexity, fieldExtensionsEstimator, simpleEstimator } from "graphql-query-complexity"; // ... Build GraphQL schema const MAX_COMPLEXITY = 100; // Example maximum complexity // Create GraphQL server const server = new ApolloServer({ schema, // Create a plugin to allow query complexity calculation for every request plugins: [ { requestDidStart: async () => ({ async didResolveOperation({ request, document }) { /** * Provides GraphQL query analysis to be able to react on complex queries to the GraphQL server * It can be used to protect the GraphQL server against resource exhaustion and DoS attacks * More documentation can be found at https://github.com/ivome/graphql-query-complexity */ const complexity = getComplexity({ // GraphQL schema schema, // To calculate query complexity properly, // check only the requested operation // not the whole document that may contains multiple operations operationName: request.operationName, // GraphQL query document query: document, // GraphQL query variables variables: request.variables, // Add any number of estimators. The estimators are invoked in order, the first // numeric value that is being returned by an estimator is used as the field complexity // If no estimator returns a value, an exception is raised estimators: [ // Using fieldExtensionsEstimator is mandatory to make it work with type-graphql fieldExtensionsEstimator(), // Add more estimators here... // This will assign each field a complexity of 1 // if no other estimator returned a value simpleEstimator({ defaultComplexity: 1 }), ], }); // React to the calculated complexity, // like compare it with max and throw error when the threshold is reached if (complexity > MAX_COMPLEXITY) { throw new Error( `Sorry, too complicated query! ${complexity} exceeded the maximum allowed complexity of ${MAX_COMPLEXITY}`, ); } console.log("Used query complexity points:", complexity); }, }), }, ], }); // Start server const { url } = await startStandaloneServer(server, { listen: { port: 4000 } }); console.log(`GraphQL server ready at ${url}`); ``` -------------------------------- ### JWT Authentication with Apollo Server and Express Source: https://github.com/michallytek/type-graphql/blob/master/docs/authorization.md Integrate TypeGraphQL with JWT authentication using Apollo Server and Express. This example sets up JWT middleware before the GraphQL middleware to authenticate requests. ```typescript import { ApolloServer } from "@apollo/server"; import { expressMiddleware } from "@apollo/server/express4"; import express from "express"; import jwt from "express-jwt"; import bodyParser from "body-parser"; import { schema } from "./graphql/schema"; import { User } from "./User.type"; // GraphQL path const GRAPHQL_PATH = "/graphql"; // GraphQL context type Context = { user?: User; }; // Express const app = express(); // Apollo server const server = new ApolloServer({ schema }); await server.start(); // Mount a JWT or other authentication middleware that is run before the GraphQL execution app.use( GRAPHQL_PATH, jwt({ secret: "TypeGraphQL", credentialsRequired: false, }), ); // Apply GraphQL server middleware app.use( GRAPHQL_PATH, bodyParser.json(), expressMiddleware(server, { // Build context // 'req.user' comes from 'express-jwt' context: async ({ req }) => ({ user: req.user }), }), ); // Start server await new Promise(resolve => app.listen({ port: 4000 }, resolve)); console.log(`GraphQL server ready at http://localhost:4000/${GRAPHQL_PATH}`); ``` -------------------------------- ### Using a Custom PubSub System Source: https://github.com/michallytek/type-graphql/blob/master/website/versioned_docs/version-2.0.0-rc.4/subscriptions.md You can integrate any PubSub system that adheres to the `PubSub` interface, which requires `.subscribe()` and `.publish()` methods. This is crucial for production environments requiring distributed pubsub. ```typescript // Example of a custom PubSub implementation (not provided in source) // class CustomPubSub implements PubSub { // subscribe(topic: string, onMessage: (...args: any[]) => void): Promise<() => void> { /* ... */ } // publish(topic: string, ...args: any[]): void { /* ... */ } // } ``` -------------------------------- ### Creating a PubSub Instance with Topics Source: https://github.com/michallytek/type-graphql/blob/master/docs/subscriptions.md Creates a PubSub instance from `@graphql-yoga/subscription`. Optionally defines topics and their payload types using a generic type argument. ```typescript import { createPubSub } from "@graphql-yoga/subscription"; export const pubSub = createPubSub<{ NOTIFICATIONS: [NotificationPayload]; DYNAMIC_ID_TOPIC: [number, NotificationPayload]; }>(); ``` -------------------------------- ### Configure Subscription Topics Source: https://github.com/michallytek/type-graphql/blob/master/docs/subscriptions.md Configure the topics a subscription should listen to. This can be a single string, an array of strings, or a dynamic function based on subscription arguments. ```typescript class SampleResolver { // ... @Subscription({ topics: "NOTIFICATIONS", // Single topic topics: ["NOTIFICATIONS", "ERRORS"] // Or topics array topics: ({ args, context }) => args.topic // Or dynamic topic function }) newNotification(): Notification { // ... } } ``` -------------------------------- ### Define Abstract Generic Response Class Source: https://github.com/michallytek/type-graphql/blob/master/docs/generic-types.md Starts by defining a function that creates and returns an abstract class for a generic response. ```typescript export default function PaginatedResponse() { abstract class PaginatedResponseClass { // ... } return PaginatedResponseClass; } ``` -------------------------------- ### Recipe Resolver with TypeGraphQL Source: https://github.com/michallytek/type-graphql/blob/master/website/pages/snippets/testability.md Demonstrates a basic TypeGraphQL resolver for a Recipe entity, including constructor injection, queries, mutations, and field resolvers. ```typescript import { Resolver, Query, Mutation, Arg, FieldResolver, Root, } from "type-graphql"; import { Repository } from "typeorm"; import { Recipe } from "./recipe.entity"; import { RecipeInput } from "./recipe.input"; import { Rate } from "./rate.entity"; @Resolver(of => Recipe) export class RecipeResolver { constructor( private readonly recipeRepository: Repository, private readonly rateRepository: Repository, ) {} @Query(returns => Recipe) async recipe(@Arg("recipeId") recipeId: string) { return this.recipeRepository.findOneById(recipeId); } @Mutation(returns => Recipe) async addRecipe(@Arg("recipe") recipeInput: RecipeInput) { const newRecipe = this.recipeRepository.create(recipeInput); return this.recipeRepository.save(newRecipe); } @FieldResolver() ratings(@Root() recipe: Recipe) { return this.rateRepository.find({ recipeId: recipe.id }); } } ``` -------------------------------- ### Accessing Extensions Metadata in Middleware Source: https://github.com/michallytek/type-graphql/blob/master/website/blog/2020-08-19-devto-article.md Example of a middleware function that reads custom metadata (roles) from field extensions using GraphQLResolveInfo. ```typescript export const ExtensionsMiddleware: MiddlewareFn = async ({ info }, next) => { const { extensions } = info.parentType.getFields()[info.fieldName]; console.log(extensions?.roles); // log the metadata return next(); }; ``` -------------------------------- ### Intercept and Modify Resolver Result Source: https://github.com/michallytek/type-graphql/blob/master/docs/middlewares.md Middleware that intercepts the resolver's result and can modify it. This example replaces a specific string with another. ```typescript export const CompetitorInterceptor: MiddlewareFn = async (_, next) => { const result = await next(); if (result === "typegql") { return "type-graphql"; } return result; }; ``` -------------------------------- ### Implement a Query Method Source: https://github.com/michallytek/type-graphql/blob/master/website/versioned_docs/version-2.0.0-rc.4/resolvers.md Create async class methods within a resolver to handle queries. This method retrieves all recipes. ```typescript import { Resolver } from "type-graphql"; import { Recipe } from "./recipe"; @Resolver() class RecipeResolver { private recipesCollection: Recipe[] = []; async recipes() { // Fake async return await this.recipesCollection; } } ``` -------------------------------- ### Azure Function Entry Point with TypeGraphQL and Apollo Server Source: https://github.com/michallytek/type-graphql/blob/master/docs/azure-functions.md This TypeScript code sets up the entry point for an Azure Function using TypeGraphQL and Apollo Server. It builds the GraphQL schema, configures Apollo Server, and exports the handler for Azure Functions. Ensure to replace 'YOUR_IMPORT_PATH' with the actual path to your resolvers. ```ts // index.ts import "reflect-metadata"; import path from "path"; import { ApolloServer } from "@apollo/server"; import { startServerAndCreateHandler } from "@as-integrations/azure-functions"; import { buildSchemaSync } from "type-graphql"; import { Container } from "typedi"; import { GraphQLFormattedError } from "graphql"; import { UserResolver } from "YOUR_IMPORT_PATH"; // TypeGraphQL Resolver import { AccountResolver } from "YOUR_IMPORT_PATH"; // TypeGraphQL Resolver // Bundle resolvers to build the schema const schema = buildSchemaSync({ // Include resolvers you'd like to expose to the API // Deployment to Azure functions might fail if // you include too much resolvers (means your app is too big) resolvers: [ UserResolver, AccountResolver, // your other resolvers ], // Only build the GraphQL schema locally // The resulting schema.graphql will be generated to the following path: // Path: /YOUR_PROJECT/src/schema.graphql emitSchemaFile: process.env.NODE_ENV === "local" ? path.resolve("./src/schema.graphql") : false, container: Container, validate: true, }); // Add schema into Apollo Server const server = new ApolloServer({ // include your schema schema, // only allow introspection in non-prod environments introspection: process.env.NODE_ENV !== "production", // you can handle errors in your own styles formatError: (err: GraphQLFormattedError) => err, }); // Start the server(less handler/function) export default startServerAndCreateHandler(server); ``` -------------------------------- ### Import Reflect Metadata Shim Source: https://github.com/michallytek/type-graphql/blob/master/docs/installation.md Import the reflect-metadata shim or core-js at the top of your entry file before using TypeGraphQL or resolvers. ```ts import "reflect-metadata"; ``` ```ts // or import "core-js/features/reflect"; ``` -------------------------------- ### Create Recipe Resolver Class Source: https://github.com/michallytek/type-graphql/blob/master/docs/getting-started.md Implement a resolver class for the Recipe type, including constructor injection for RecipeService and defining query and mutation methods. ```typescript @Resolver(Recipe) class RecipeResolver { constructor(private recipeService: RecipeService) {} @Query(returns => Recipe) async recipe(@Arg("id") id: string) { const recipe = await this.recipeService.findById(id); if (recipe === undefined) { throw new RecipeNotFoundError(id); } return recipe; } @Query(returns => [Recipe]) recipes(@Args() { skip, take }: RecipesArgs) { return this.recipeService.findAll({ skip, take }); } @Mutation(returns => Recipe) @Authorized() addRecipe( @Arg("newRecipeData") newRecipeData: NewRecipeInput, @Ctx("user") user: User, ): Promise { return this.recipeService.addNew({ data: newRecipeData, user }); } @Mutation(returns => Boolean) @Authorized(Roles.Admin) async removeRecipe(@Arg("id") id: string) { try { await this.recipeService.removeById(id); return true; } catch { return false; } } } ``` -------------------------------- ### Add Specific Mutations to Extended Resolver Source: https://github.com/michallytek/type-graphql/blob/master/website/versioned_docs/version-2.0.0-rc.4/inheritance.md Extend a base resolver class and add new mutations or queries specific to the entity. This example adds an `addPerson` mutation to the `PersonResolver`. ```typescript import { Person, PersonInput } from "./person.entity"; // Assuming Person and PersonInput are defined elsewhere import { ClassType, Resolver, Query, Arg, Int, Mutation } from "type-graphql"; function createBaseResolver(suffix: string, objectTypeCls: T) { @Resolver() abstract class BaseResolver { protected items: T[] = []; @Query(type => [objectTypeCls], { name: `getAll${suffix}` }) async getAll(@Arg("first", type => Int) first: number): Promise { return this.items.slice(0, first); } } return BaseResolver; } const PersonBaseResolver = createBaseResolver("person", Person); @Resolver(of => Person) export class PersonResolver extends PersonBaseResolver { @Mutation() addPerson(@Arg("input") personInput: PersonInput): Person { this.items.push(personInput); return personInput; } } ``` -------------------------------- ### Registering Global Middleware Source: https://github.com/michallytek/type-graphql/blob/master/docs/middlewares.md Configure global middleware for all queries, mutations, and subscriptions by providing an array of middleware classes to the `globalMiddlewares` property in the `buildSchema` configuration. ```typescript const schema = await buildSchema({ resolvers: [RecipeResolver], globalMiddlewares: [ErrorInterceptor, ResolveTime], }); ``` -------------------------------- ### Implementing an Interface with Method Override Source: https://github.com/michallytek/type-graphql/blob/master/docs/interfaces.md An object type implementing an interface must override abstract methods. This example shows the Person class providing an implementation for the avatar method. ```typescript import { ObjectType, Field, Arg } from "type-graphql"; import { IPerson } from "./IPerson"; // Assuming IPerson is in a separate file @ObjectType({ implements: IPerson }) class Person extends IPerson { avatar(size: number): string { return `http://i.pravatar.cc/${size}`; } } ``` -------------------------------- ### Create a Simple CurrentUser Parameter Decorator Source: https://github.com/michallytek/type-graphql/blob/master/docs/custom-decorators.md This snippet shows how to create a basic parameter decorator that extracts the current user from the context. Use this for simple data extraction to make resolvers more unit test friendly. ```typescript function CurrentUser() { return createParameterDecorator(({ context }) => context.currentUser); } ``` -------------------------------- ### Basic Recipe Input with Validation Source: https://github.com/michallytek/type-graphql/blob/master/docs/validation.md Decorate input fields with class-validator decorators like @MaxLength and @Length to define validation rules. ```ts import { MaxLength, Length } from "class-validator"; @InputType() export class RecipeInput { @Field() @MaxLength(30) title: string; @Field({ nullable: true }) @Length(30, 255) description?: string; } ``` -------------------------------- ### Define GraphQL Object Type with Decorators Source: https://github.com/michallytek/type-graphql/blob/master/README.md Example of defining a 'Recipe' object type using TypeGraphQL decorators. This class definition translates directly into a GraphQL schema type. ```typescript import { ObjectType, Field, ID } from "type-graphql"; @ObjectType() class Recipe { @Field(type => ID) id: string; @Field() title: string; @Field(type => [Rate]) ratings: Rate[]; @Field({ nullable: true }) averageRating?: number; } ``` -------------------------------- ### Programmatically Emit Schema Definition File Source: https://github.com/michallytek/type-graphql/blob/master/docs/emit-schema.md Use `emitSchemaDefinitionFile` or `emitSchemaDefinitionFileSync` to emit the schema definition file programmatically. This is useful for testing scripts or local development file watching. ```typescript import { emitSchemaDefinitionFile } from "type-graphql"; // ... hypotheticalFileWatcher.watch("./src/**/*.{resolver,type,input,arg}.ts", async () => { const schema = getSchemaNotFromBuildSchemaFunction(); await emitSchemaDefinitionFile("/path/to/folder/schema.graphql", schema); }); ``` -------------------------------- ### Defining Interface Type with Arguments Source: https://github.com/michallytek/type-graphql/blob/master/docs/interfaces.md Declare that an interface accepts arguments using the @Arg decorator within the field resolver. This example shows an avatar field that takes a size argument. ```typescript import { InterfaceType, Field, Arg } from "type-graphql"; @InterfaceType() abstract class IPerson { @Field() avatar(@Arg("size") size: number): string { return `http://i.pravatar.cc/${size}`; } } ``` -------------------------------- ### Registering PubSub Instance in buildSchema Source: https://github.com/michallytek/type-graphql/blob/master/docs/subscriptions.md Registers the created PubSub instance within the `buildSchema` function options to make it available for TypeGraphQL. ```typescript import { buildSchema } from "type-graphql"; import { pubSub } from "./pubsub"; const schema = await buildSchema({ resolver, pubSub, }); ``` -------------------------------- ### Extending Interface Signature with Additional Arguments Source: https://github.com/michallytek/type-graphql/blob/master/docs/interfaces.md To add arguments to an interface field in an implementing class, redeclare the entire field signature with the new arguments. This example adds a 'format' argument to the avatar field. ```typescript import { ObjectType, Field, Arg } from "type-graphql"; import { IPerson } from "./IPerson"; // Assuming IPerson is in a separate file @ObjectType({ implements: IPerson }) class Person implements IPerson { @Field() avatar(@Arg("size") size: number, @Arg("format") format: string): string { return `http://i.pravatar.cc/${size}.${format}`; } } ``` -------------------------------- ### Setting up Apollo Server with Scoped Containers and TypeDI Source: https://github.com/michallytek/type-graphql/blob/master/docs/dependency-injection.md Integrates Apollo Server with TypeDI to provide a unique, request-scoped container for each request. It sets up the context to include a requestId and the corresponding container, and stores the container within the context itself. ```typescript import { ApolloServer } from "@apollo/server"; import { startStandaloneServer } from "@apollo/server/standalone"; import { Container } from "typedi"; // Create GraphQL server const server = new ApolloServer({ // GraphQL schema schema, }); // Start server const { url } = await startStandaloneServer(server, { listen: { port: 4000 }, // Provide unique context with 'requestId' for each request context: async () => { const requestId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); // uuid-like const container = Container.of(requestId.toString()); // Get scoped container const context = { requestId, container }; // Create context container.set("context", context); // Set context or other data in container return context; }, }); console.log(`GraphQL server ready at ${url}`); ``` -------------------------------- ### Registering Scoped Container with TypeDI Source: https://github.com/michallytek/type-graphql/blob/master/docs/dependency-injection.md Configure TypeGraphQL to use a scoped container by providing a container resolver function that retrieves a request-specific container instance. This example uses TypeDI and assumes context.requestId is available. ```typescript await buildSchema({ container: (({ context }: ResolverData) => Container.of(context.requestId)); }; ``` -------------------------------- ### Integrating String-Based Directive Type Definitions Source: https://github.com/michallytek/type-graphql/blob/master/docs/directives.md When a directive package exports string-based type definitions, merge them with the TypeGraphQL schema and then apply the directive transformer. This example uses `@graphql-tools/schema` and a fake directive package. ```typescript import { mergeSchemas } from "@graphql-tools/schema"; import { renameDirective } from "fake-rename-directive-package"; import { buildSchema } from "type-graphql"; import { SampleResolver } from "./sample.resolver"; // Build TypeGraphQL executable schema const schemaSimple = await buildSchema({ resolvers: [SampleResolver], }); // Merge schema with sample directive type definitions const schemaMerged = mergeSchemas({ schemas: [schemaSimple], // Register the directives definitions typeDefs: [renameDirective.typeDefs], }); // Transform and obtain the final schema const schema = renameDirective.transformer(schemaMerged); ``` -------------------------------- ### Add Prisma Generator Source: https://github.com/michallytek/type-graphql/blob/master/docs/prisma.md Add the typegraphql-prisma generator to your schema.prisma file. ```sh generator typegraphql { provider = "typegraphql-prisma" } ``` -------------------------------- ### AWS Lambda Integration with TypeGraphQL Schema Caching Source: https://github.com/michallytek/type-graphql/blob/master/docs/aws-lambda.md This snippet shows how to integrate TypeGraphQL with AWS Lambda. It caches the built schema and ApolloServer instance to optimize performance by building them only once. Ensure you have `aws-lambda` and `apollo-server-lambda` installed. ```typescript import { APIGatewayProxyHandlerV2 } from "aws-lambda"; import { ApolloServer } from "apollo-server-lambda"; let cachedSchema: GraphQLSchema | null = null; let cachedServer: ApolloServer | null = null; export const handler: APIGatewayProxyHandlerV2 = async (event, context, callback) => { // build TypeGraphQL executable schema only once, then read it from local "cached" variable cachedSchema ??= await buildSchema({ resolvers: [RecipeResolver], }); // create the GraphQL server only once cachedServer ??= new ApolloServer({ schema: cachedSchema }); // make a handler for `aws-lambda` return cachedServer.createHandler({})(event, context, callback); }; ``` -------------------------------- ### Package.json Configuration for ESM Source: https://github.com/michallytek/type-graphql/blob/master/docs/esm.md Set the 'type' option to 'module' in your package.json to enable ESM. ```json { "type": "module" } ``` -------------------------------- ### GraphQL Schema Definition (SDL) for ArgsType Source: https://github.com/michallytek/type-graphql/blob/master/docs/resolvers.md The resulting GraphQL schema definition (SDL) for a query using `@ArgsType` with default values. ```graphql type Query { recipes(skip: Int = 0, take: Int = 25, title: String): [Recipe!] } ``` -------------------------------- ### Build Schema with Resolvers Source: https://github.com/michallytek/type-graphql/blob/master/docs/bootstrap.md Use `buildSchema` to create an executable GraphQL schema from resolver classes. Ensure all necessary resolvers are included in the `resolvers` array. ```typescript import { FirstResolver, SecondResolver } from "./resolvers"; // ... const schema = await buildSchema({ resolvers: [FirstResolver, SecondResolver], }); ``` -------------------------------- ### Applying Directives in TypeGraphQL Source: https://github.com/michallytek/type-graphql/blob/master/website/blog/2020-08-19-devto-article.md Demonstrates how to apply a GraphQL directive using the @Directive decorator in a TypeGraphQL resolver. ```typescript @Resolver() class FooBarResolver { @Directive("@auth(requires: USER)") @Query() foobar(): string { return "foobar"; } } ``` -------------------------------- ### Azure Function HTTP Trigger Configuration Source: https://github.com/michallytek/type-graphql/blob/master/docs/azure-functions.md This JSON configuration defines the bindings for an Azure Function, specifically setting up an HTTP trigger for a GraphQL endpoint. It allows anonymous access and supports GET, POST, and OPTIONS methods on the '/graphql' route. ```json { "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "route": "graphql", "methods": ["get", "post", "options"] }, { "type": "http", "direction": "out", "name": "$return" } ], "scriptFile": "../dist/handler-graphql/index.js" } ``` -------------------------------- ### Emit Schema File Automatically on Build Source: https://github.com/michallytek/type-graphql/blob/master/docs/emit-schema.md Pass `emitSchemaFile: true` to `buildSchema` options to automatically create `schema.graphql` in the project's root. This is useful for integrating with GraphQL ecosystem tools. ```typescript 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 }, }); ``` -------------------------------- ### Commit changes with git Source: https://github.com/michallytek/type-graphql/blob/master/CONTRIBUTING.md Use the git commit -a command to stage and commit your changes. This is a convenient way to commit all modified tracked files. ```shell git commit -a ``` -------------------------------- ### Create a new git branch Source: https://github.com/michallytek/type-graphql/blob/master/CONTRIBUTING.md When preparing to make changes, create a new git branch off the master branch. This isolates your work and makes it easier to manage. ```shell git checkout -b my-fix-branch master ``` -------------------------------- ### Implement Service with Injected Dependencies Source: https://github.com/michallytek/type-graphql/blob/master/docs/dependency-injection.md Define services that can have their own dependencies injected. Use decorators like `@Service()` and `@Inject()` from TypeDI. ```typescript import { Service, Inject } from "typedi"; @Service() export class RecipeService { @Inject("SAMPLE_RECIPES") private readonly items: Recipe[], async getAll() { return this.items; } async getOne(id: string) { return this.items.find(item => item.id === id); } } ``` -------------------------------- ### Enable Decorators in tsconfig.json Source: https://github.com/michallytek/type-graphql/blob/master/docs/installation.md Configure tsconfig.json to enable experimental decorators and emit decorator metadata, which are essential for TypeGraphQL. ```json { "emitDecoratorMetadata": true, "experimentalDecorators": true } ``` -------------------------------- ### Define a Subscription Resolver Source: https://github.com/michallytek/type-graphql/blob/master/docs/subscriptions.md Define a basic subscription resolver using the @Subscription() decorator. This sets up a method that will be called when a relevant topic event occurs. ```typescript class SampleResolver { // ... @Subscription() newNotification(): Notification { // ... } } ``` -------------------------------- ### Sample Mutation for Adding a New Comment Source: https://github.com/michallytek/type-graphql/blob/master/docs/subscriptions.md This mutation adds a new comment. It does not trigger any subscriptions itself but serves as a base for demonstrating subscription triggering. ```typescript class SampleResolver { // ... @Mutation(returns => Boolean) async addNewComment(@Arg("comment") input: CommentInput) { const comment = this.commentsService.createNew(input); await this.commentsRepository.save(comment); return true; } } ``` -------------------------------- ### Create Mutation Resolver with Input Type Source: https://github.com/michallytek/type-graphql/blob/master/website/versioned_docs/version-2.0.0-rc.4/resolvers.md Use @Mutation() and @Arg() decorators to define a mutation that accepts an input type. Access context using @Ctx(). ```typescript import { Resolver, Mutation, Arg, Ctx } from "typegraphql-typescript"; import { Recipe } from "./recipe"; import { AddRecipeInput } from "./add-recipe.input"; import { Context } from "./context"; import { RecipesUtils } from "./recipes.utils"; @Resolver() class RecipeResolver { private recipesCollection: Recipe[] = []; @Mutation() addRecipe(@Arg("data") newRecipeData: AddRecipeInput, @Ctx() ctx: Context): Recipe { // Example implementation const recipe = RecipesUtils.create(newRecipeData, ctx.user); this.recipesCollection.push(recipe); return recipe; } } ``` -------------------------------- ### Integrate TypeDefs and Resolvers with Apollo Link State Source: https://github.com/michallytek/type-graphql/blob/master/docs/bootstrap.md This snippet shows how to use the `typeDefs` and `resolvers` generated by `buildTypeDefsAndResolvers` with `apollo-link-state` for client-side state management. ```typescript import { withClientState } from "apollo-link-state"; import { buildTypeDefsAndResolvers } from "type-graphql"; // Assuming FirstResolver and SecondResolver are defined elsewhere // class FirstResolver {} // class SecondResolver {} const { typeDefs, resolvers } = await buildTypeDefsAndResolvers({ resolvers: [FirstResolver, SecondResolver], }); const stateLink = withClientState({ // ... Other options like `cache` typeDefs, resolvers, }); // ... Rest of `ApolloClient` initialization code ``` -------------------------------- ### Define Recipe Type Class Source: https://github.com/michallytek/type-graphql/blob/master/docs/getting-started.md Define the basic TypeScript class for the Recipe type, mirroring the GraphQL schema structure. ```typescript class Recipe { id: string; title: string; description?: string; creationDate: Date; ingredients: string[]; } ``` -------------------------------- ### Resolver Method for Recipes Query Source: https://github.com/michallytek/type-graphql/blob/master/docs/resolvers.md Implement an async method within a resolver class to handle a GraphQL query. This method returns a collection of recipes. ```typescript import { Resolver } from "type-graphql"; @Resolver() class RecipeResolver { private recipesCollection: Recipe[] = []; async recipes() { // Fake async return await this.recipesCollection; } } ``` -------------------------------- ### Decorate Recipe Type with TypeGraphQL Decorators Source: https://github.com/michallytek/type-graphql/blob/master/docs/getting-started.md Apply TypeGraphQL decorators to the Recipe class and its properties to map them to GraphQL types and fields. ```typescript @ObjectType() class Recipe { @Field(type => ID) id: string; @Field() title: string; @Field({ nullable: true }) description?: string; @Field() creationDate: Date; @Field(type => [String]) ingredients: string[]; } ``` -------------------------------- ### Define Input Type and Arguments Source: https://github.com/michallytek/type-graphql/blob/master/website/blog/2018-03-25-medium-article.md Defines a class for input data and another for query arguments using TypeGraphQL decorators. Includes validation decorators from class-validator. ```typescript import { MaxArraySize, MaxLength, MinLength } from "class-validator"; import { Field, InputType, Int, ArgsType } from "type-graphql"; @InputType() class NewRecipeDataInput { @Field() @MaxLength(30) title: string; @Field({ nullable: true }) @Length(30, 255) description?: string; @Field(type => [String]) @MaxArraySize(30) ingredients: string[]; } @ArgsType() class RecipesArgs { @Field(type => Int, { nullable: true }) @Min(0) skip: number = 0; @Field(type => Int, { nullable: true }) @Min(1) @Max(50) take: number = 25; } ``` -------------------------------- ### Creating a Custom Resolver Class Decorator Source: https://github.com/michallytek/type-graphql/blob/master/docs/custom-decorators.md Implement a custom resolver class decorator using `createResolverClassMiddlewareDecorator`. This allows applying common logic to all methods within a resolver class. ```typescript export function ValidateArgs(schema: JoiSchema) { return createResolverClassMiddlewareDecorator(async ({ args }, next) => { // Middleware code that uses custom decorator arguments // e.g. Validation logic based on schema using 'joi' await joiValidate(schema, args); return next(); }); } ``` -------------------------------- ### Implement ResolverInterface for Type Safety Source: https://github.com/michallytek/type-graphql/blob/master/docs/resolvers.md Implement ResolverInterface for enhanced type safety, ensuring method return types and parameter types match the Recipe class. ```typescript @Resolver(of => Recipe) class RecipeResolver implements ResolverInterface { // Queries and mutations @FieldResolver() averageRating(@Root() recipe: Recipe) { // ... } } ``` -------------------------------- ### Push branch to GitHub Source: https://github.com/michallytek/type-graphql/blob/master/CONTRIBUTING.md After committing your changes, push your new branch to your GitHub repository to make it available for a pull request. ```shell git push origin my-fix-branch ``` -------------------------------- ### Applying @Directive to Query and Field Resolver Source: https://github.com/michallytek/type-graphql/blob/master/docs/directives.md Shows how to apply directives to query methods and field resolver methods in TypeGraphQL. ```typescript @Resolver(of => Foo) class FooBarResolver { @Directive("@auth(requires: ANY)") @Query() foobar(@Args() { baz }: FooBarArgs): string { return "foobar"; } @Directive("@auth(requires: ADMIN)") @FieldResolver() bar(): string { return "foobar"; } } ```