CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nestjs--graphql

GraphQL integration for the NestJS framework enabling developers to build GraphQL APIs using decorators and TypeScript

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

resolvers.mddocs/

Resolver Development

Tools and utilities for building GraphQL resolvers including field resolvers, context access, argument handling, and execution context management. This module provides the runtime infrastructure for GraphQL query execution in NestJS applications.

Capabilities

Field Resolvers

Decorators and utilities for creating computed fields and reference resolvers in GraphQL schemas.

/**
 * Marks a method as a GraphQL Field Resolver for computed fields
 * @param name - Optional field name (defaults to method name)
 * @param options - Configuration options for the field resolver
 */
function ResolveField(name?: string, options?: FieldOptions): MethodDecorator;

/**
 * Marks a method as a GraphQL Reference Resolver for Apollo Federation
 * Used to resolve entity references across federated services
 */
function ResolveReference(): MethodDecorator;

/**
 * Legacy alias for ResolveField (deprecated in favor of ResolveField)
 * @param name - Optional field name
 * @param options - Configuration options
 */
function ResolveProperty(name?: string, options?: FieldOptions): MethodDecorator;

Usage Examples:

import { Resolver, ResolveField, ResolveReference, Parent, Args } from "@nestjs/graphql";

@Resolver(() => User)
class UserResolver {
  // Computed field resolver
  @ResolveField(() => String)
  fullName(@Parent() user: User): string {
    return `${user.firstName} ${user.lastName}`;
  }
  
  // Async field resolver with database lookup
  @ResolveField(() => [Post])
  async posts(@Parent() user: User): Promise<Post[]> {
    return this.postService.findByUserId(user.id);
  }
  
  // Field resolver with arguments
  @ResolveField(() => [Post])
  recentPosts(
    @Parent() user: User,
    @Args('limit', { defaultValue: 10 }) limit: number
  ): Promise<Post[]> {
    return this.postService.findRecentByUserId(user.id, limit);
  }
  
  // Federation reference resolver
  @ResolveReference()
  resolveReference(reference: { __typename: string; id: string }): Promise<User> {
    return this.userService.findById(reference.id);
  }
}

Execution Context

Utilities for accessing GraphQL-specific execution context within resolvers and guards.

/**
 * GraphQL-specific execution context wrapper providing access to GraphQL resolver arguments
 */
export class GqlExecutionContext {
  /**
   * Create GraphQL execution context from standard NestJS execution context
   * @param context - Standard NestJS execution context
   * @returns GraphQL-specific execution context
   */
  static create(context: ExecutionContext): GqlExecutionContext;
  
  /**
   * Get the context type (always returns 'graphql')
   * @returns Context type string
   */
  getType(): string;
  
  /**
   * Get the GraphQL root/parent object
   * @returns Root object for the current resolver
   */
  getRoot<T = any>(): T;
  
  /**
   * Get GraphQL resolver arguments
   * @returns Arguments object passed to the resolver
   */
  getArgs<T = any>(): T;
  
  /**
   * Get GraphQL context object
   * @returns GraphQL context containing request, response, and custom data
   */
  getContext<T = any>(): T;
  
  /**
   * Get GraphQL resolve info object
   * @returns GraphQL resolve info containing field selection and metadata
   */
  getInfo(): GraphQLResolveInfo;
}

/**
 * Type alias for GraphQL execution context
 */
type GraphQLExecutionContext = GqlExecutionContext;

/**
 * Union type for GraphQL context types
 */
type GqlContextType = 'graphql';

Usage Examples:

import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common";
import { GqlExecutionContext } from "@nestjs/graphql";

// Using in a Guard
@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const gqlContext = GqlExecutionContext.create(context);
    const ctx = gqlContext.getContext();
    const user = ctx.req.user;
    return !!user;
  }
}

// Using in an Interceptor
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const gqlContext = GqlExecutionContext.create(context);
    const info = gqlContext.getInfo();
    console.log(`Executing GraphQL field: ${info.fieldName}`);
    return next.handle();
  }
}

Arguments Host

Service for accessing GraphQL resolver arguments in a structured way.

/**
 * Host service for accessing GraphQL resolver arguments
 */
export class GqlArgumentsHost {
  /**
   * Get the GraphQL root/parent object
   * @returns Root object for the current resolver
   */
  getRoot<T = any>(): T;
  
  /**
   * Get GraphQL resolver arguments
   * @returns Arguments object passed to the resolver
   */
  getArgs<T = any>(): T;
  
  /**
   * Get GraphQL context object
   * @returns GraphQL context containing request, response, and custom data
   */
  getContext<T = any>(): T;
  
  /**
   * Get GraphQL resolve info object
   * @returns GraphQL resolve info containing field selection and metadata
   */
  getInfo(): GraphQLResolveInfo;
}

/**
 * Interface for GraphQL arguments host
 */
interface GraphQLArgumentsHost {
  getRoot<T = any>(): T;
  getArgs<T = any>(): T;
  getContext<T = any>(): T;
  getInfo(): GraphQLResolveInfo;
}

Base Explorer Service

Base service class for exploring and processing GraphQL metadata from NestJS modules.

/**
 * Base class for services that explore NestJS modules for GraphQL metadata
 */
export abstract class BaseExplorerService {
  /**
   * Explore modules and extract metadata
   * @param modules - Array of NestJS modules to explore
   * @returns Extracted metadata
   */
  protected abstract explore(modules: any[]): any;
  
  /**
   * Filter and process discovered providers
   * @param providers - Array of providers to process
   * @returns Processed providers
   */
  protected abstract filterProviders(providers: any[]): any[];
}

Resolver Context Types

Type definitions for resolver context handling and argument extraction.

/**
 * Interface for GraphQL context containing request and response objects
 */
interface GraphQLContext {
  /** HTTP request object */
  req: any;
  /** HTTP response object */
  res: any;
  /** Connection object for subscriptions */
  connection?: any;
  /** Additional context data */
  [key: string]: any;
}

/**
 * Type for resolver function signatures
 */
type ResolverFn<TSource = any, TContext = any, TArgs = any, TResult = any> = (
  source: TSource,
  args: TArgs,
  context: TContext,
  info: GraphQLResolveInfo
) => TResult | Promise<TResult>;

/**
 * Type for field resolver functions
 */
type FieldResolverFn<TSource = any, TContext = any, TArgs = any, TResult = any> = (
  source: TSource,
  args: TArgs,
  context: TContext,
  info: GraphQLResolveInfo
) => TResult | Promise<TResult>;

Advanced Resolver Patterns

Common patterns and utilities for building complex GraphQL resolvers.

/**
 * Interface for implementing resolve type functions for union and interface types
 */
interface ResolveTypeFn<TSource = any, TContext = any> {
  (value: TSource, context: TContext, info: GraphQLResolveInfo): string | Promise<string>;
}

/**
 * Options for configuring resolver validation
 */
interface ResolverValidationOptions {
  /** Whether to require resolvers for all fields */
  requireResolversForResolveType?: boolean;
  /** Whether to require resolvers for all args */
  requireResolversForArgs?: boolean;
  /** Whether to require resolvers for non-scalar fields */
  requireResolversForNonScalar?: boolean;
  /** Whether to require resolvers for all fields */
  requireResolversForAllFields?: boolean;
}

Advanced Usage Examples:

import { Resolver, ResolveField, Parent, Args, Context, Info } from "@nestjs/graphql";
import { GraphQLResolveInfo } from "graphql";

@Resolver(() => User)
export class AdvancedUserResolver {
  constructor(
    private userService: UserService,
    private postService: PostService,
    private dataLoader: DataLoaderService
  ) {}

  // Resolver with data loader for N+1 problem prevention
  @ResolveField(() => [Post])
  async posts(@Parent() user: User): Promise<Post[]> {
    return this.dataLoader.postsByUserId.load(user.id);
  }
  
  // Resolver with field selection optimization
  @ResolveField(() => Profile)
  async profile(
    @Parent() user: User,
    @Info() info: GraphQLResolveInfo
  ): Promise<Profile> {
    const selectedFields = this.getSelectedFields(info);
    return this.userService.findProfileWithFields(user.id, selectedFields);
  }
  
  // Resolver with complex arguments and validation
  @ResolveField(() => [Post])
  async postsByCategory(
    @Parent() user: User,
    @Args('category') category: string,
    @Args('pagination') pagination: PaginationArgs,
    @Context() context: GraphQLContext
  ): Promise<Post[]> {
    // Access user from context for authorization
    const currentUser = context.req.user;
    return this.postService.findByUserAndCategory(
      user.id, 
      category, 
      pagination,
      currentUser
    );
  }
  
  // Federation resolver with error handling
  @ResolveReference()
  async resolveReference(
    reference: { __typename: string; id: string }
  ): Promise<User | null> {
    try {
      return await this.userService.findById(reference.id);
    } catch (error) {
      // Log error and return null for graceful degradation
      console.error(`Failed to resolve user reference: ${reference.id}`, error);
      return null;
    }
  }
  
  private getSelectedFields(info: GraphQLResolveInfo): string[] {
    // Helper method to extract selected fields from GraphQL info
    // Implementation would parse the selection set
    return [];
  }
}

// Union type resolver
@Resolver(() => SearchResult)
export class SearchResultResolver {
  @ResolveField()
  __resolveType(value: any): string {
    if (value instanceof User) return 'User';
    if (value instanceof Post) return 'Post';
    return null;
  }
}

Error Handling in Resolvers

Best practices and utilities for handling errors in GraphQL resolvers.

/**
 * GraphQL-specific error types
 */
import { 
  GraphQLError,
  UserInputError,
  AuthenticationError,
  ForbiddenError,
  ApolloError
} from 'apollo-server-express';

/**
 * Custom GraphQL error with extensions
 */
class CustomGraphQLError extends GraphQLError {
  constructor(
    message: string,
    code: string,
    extensions?: Record<string, any>
  ) {
    super(message, null, null, null, null, null, {
      code,
      ...extensions,
    });
  }
}

Error Handling Examples:

import { UserInputError, AuthenticationError } from 'apollo-server-express';

@Resolver(() => User)
export class UserResolver {
  @Query(() => User)
  async user(@Args('id') id: string, @Context() context: any): Promise<User> {
    // Authentication check
    if (!context.user) {
      throw new AuthenticationError('You must be logged in to view user details');
    }
    
    // Input validation
    if (!id || typeof id !== 'string') {
      throw new UserInputError('Invalid user ID provided', {
        invalidArgs: ['id'],
      });
    }
    
    const user = await this.userService.findById(id);
    
    if (!user) {
      throw new UserInputError('User not found', {
        code: 'USER_NOT_FOUND',
        userId: id,
      });
    }
    
    return user;
  }
}

docs

federation.md

index.md

module-configuration.md

resolvers.md

schema-building.md

schema-decorators.md

services.md

subscriptions.md

type-system.md

tile.json