🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@fluojs/graphql

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fluojs/graphql

Decorator-based GraphQL module, schema exposure, and execution pipeline for Fluo.

latest
Source
npmnpm
Version
1.0.4
Version published
Weekly downloads
26
-36.59%
Maintainers
1
Weekly downloads
 
Created
Source

@fluojs/graphql

English 한국어

Decorator-based GraphQL integration for fluo. Built on GraphQL Yoga, it provides a high-performance, specification-compliant GraphQL execution pipeline with deep DI integration and first-party DataLoader support.

Table of Contents

Installation

pnpm add @fluojs/graphql graphql graphql-yoga

When to Use

  • When building type-safe GraphQL APIs using TypeScript decorators (Code-first).
  • When integrating an existing executable GraphQLSchema object into a fluo application.
  • When you need seamless dependency injection within GraphQL resolvers, including request-scoped providers.
  • When performing efficient data fetching using request-scoped DataLoader patterns.

Quick Start

Register GraphqlModule.forRoot(...) and define a resolver using standard decorators. @fluojs/graphql currently exposes a synchronous module entrypoint only; there is no GraphqlModule.forRootAsync(...) contract.

You can also pass an executable GraphQLSchema via schema when you want schema-first integration instead of code-first resolver discovery.

import { Module } from '@fluojs/core';
import { bootstrapNodeApplication } from '@fluojs/runtime/node';
import { GraphqlModule, Query, Resolver, Arg } from '@fluojs/graphql';

class HelloInput {
  @Arg('name')
  name = '';
}

@Resolver()
class HelloResolver {
  @Query({ input: HelloInput })
  hello(input: HelloInput): string {
    return `Hello, ${input.name}!`;
  }
}

@Module({
  imports: [
    GraphqlModule.forRoot({
      resolvers: [HelloResolver]
    })
  ],
  providers: [HelloResolver]
})
class AppModule {}

const app = await bootstrapNodeApplication(AppModule);
await app.listen(3000);
// curl -X POST http://localhost:3000/graphql \
//   -H "Content-Type: application/json" \
//   -d '{"query": "{ hello(name: \"fluo\") }"}'

Core Capabilities

Code-first Resolvers

fluo uses standard decorators to define your GraphQL schema. Use @Resolver, @Query, @Mutation, and @Subscription to map class methods to GraphQL operations. GraphQL arguments are declared on input DTO fields with @Arg(...), then passed to the resolver method through the operation input option.

@fluojs/graphql currently supports root operation resolvers only. Object field-resolver patterns such as author(book, context) remain design-only and are documented in packages/graphql/field-resolver-rfc.md, not in the runtime contract.

Request-Scoped DataLoaders

Efficiently solve the N+1 problem with built-in DataLoader integration. Loaders are automatically isolated per GraphQL operation.

import { createDataLoader, type GraphQLContext } from '@fluojs/graphql';

const userLoader = createDataLoader(async (ids: string[]) => {
  const users = await userService.findByIds(ids);
  return ids.map(id => users.find(u => u.id === id));
});

class UserInput {
  @Arg('id')
  id = '';
}

@Resolver()
class UserResolver {
  @Query({ input: UserInput })
  async user(input: UserInput, context: GraphQLContext) {
    return userLoader(context).load(input.id);
  }
}

Resolver Lifecycle Contracts

  • Singleton resolvers are the default and are resolved from the application container for every operation.
  • Resolvers that inject request-scoped providers must also be marked with @Scope('request'); this keeps DI lifetime rules explicit and avoids singleton-to-request dependency mismatches.
  • @fluojs/graphql creates one operation-scoped DI container for each HTTP GraphQL request or websocket subscription operation, shares it across resolver calls in that operation, and disposes it when the operation completes or the websocket operation disconnects.
  • Resolver methods receive a GraphQLContext whose built-in fields expose the underlying fluo request, the authenticated HTTP principal when middleware or guards set one, websocket connectionParams and socket for websocket subscriptions, and any custom fields returned from GraphqlModule.forRoot({ context }).
  • Request-scoped DataLoader helpers use the same GraphQLContext operation boundary, so loader caches are shared only within one GraphQL operation.
  • Application shutdown unregisters the websocket transport, closes live websocket clients, and disposes any still-active websocket operation containers through the same request-scoped provider teardown path used when an operation completes normally.
import { Inject, Scope } from '@fluojs/core';
import { Query, Resolver } from '@fluojs/graphql';

@Scope('request')
class RequestState {
  private static nextId = 0;
  readonly requestId = `request-${++RequestState.nextId}`;
}

@Inject(RequestState)
@Scope('request')
@Resolver()
class RequestResolver {
  constructor(private readonly state: RequestState) {}

  @Query('requestId')
  requestId(): string {
    return this.state.requestId;
  }
}

Protocol Support

  • HTTP: Standard GET/POST queries and mutations.
  • SSE: Subscriptions over Server-Sent Events (default).
  • WebSockets: Optional graphql-ws support for real-time subscriptions when the active adapter exposes a Node HTTP/S server with upgrade listeners (for example, the Node HTTP adapter).

HTTP queries/mutations and the default SSE subscription path run through fluo's portable HTTP abstraction. The optional websocket transport is intentionally narrower: it requires a server-backed Node HTTP/S adapter surface, so Bun, Deno, and Cloudflare Workers deployments should keep the default SSE path unless their adapter exposes compatible upgrade listeners.

GraphqlModule.forRoot({
  subscriptions: {
    websocket: {
      enabled: true,
      limits: {
        maxConnections: 100,
        maxPayloadBytes: 64 * 1024,
        maxOperationsPerConnection: 25,
      },
    }
  }
})

@Subscription({ topics }) is not supported. Subscription resolvers must return an AsyncIterable.

Operational Guardrails

  • Schema introspection is disabled by default unless you explicitly enable graphiql or set introspection: true.
  • Request validation budgets are enabled by default with conservative limits for document depth, field complexity, and aggregate query cost.
  • graphiql defaults to false. introspection follows graphiql unless set explicitly, so production apps stay private by default while local GraphiQL sessions can opt in.
  • limits accepts request validation budgets or false; use false only when equivalent controls exist outside fluo.
  • Streaming GraphQL responses cancel the upstream fetch body when the downstream response stream closes or errors, so SSE subscription resources are released promptly.
  • Bootstrap failures after GraphQL schema resolution restore the package's temporary graphql/jsutils/instanceOf patch before rethrowing, so failed startups do not leak process-wide GraphQL behavior into later app attempts.
  • WebSocket subscriptions use separate transport budgets by default: 100 concurrent connections, 64 KiB maximum payload size, and 25 active operations per connection.
  • subscriptions.websocket.enabled defaults to false; enabling it requires a Node HTTP/S adapter with upgrade support. connectionInitWaitTimeoutMs is forwarded to graphql-ws for connection initialization, and keepAliveMs controls websocket keepalive pings when configured.
  • Set subscriptions.websocket.limits = false only when you intentionally need unbounded websocket behavior and can enforce equivalent controls elsewhere.
  • Pass limits: false only when you intentionally need unbounded behavior and can compensate with external controls.
GraphqlModule.forRoot({
  graphiql: false,
  introspection: false,
  limits: {
    maxDepth: 8,
    maxComplexity: 120,
    maxCost: 240,
  },
  subscriptions: {
    websocket: {
      enabled: true,
      limits: {
        maxConnections: 100,
        maxPayloadBytes: 64 * 1024,
        maxOperationsPerConnection: 25,
      },
    },
  },
  resolvers: [HelloResolver],
})

Public API

  • GraphqlModule.forRoot(options): Main entry point for GraphQL integration.
  • Resolver, Query, Mutation, Subscription: Operation decorators.
  • Arg: Input DTO field-to-GraphQL-argument mapping decorator.
  • createDataLoader, createDataLoaderMap, getRequestScopedDataLoader, createRequestScopedDataLoaderFactory, DataLoader: DataLoader factory helpers and types.
  • listOf, isGraphqlListTypeRef: Helpers for list output type references.
  • GraphQLContext and exported option/metadata types: Type definitions for GraphQL execution and module configuration.

Supported module options include schema, context, plugins, graphiql, introspection, limits, subscriptions.websocket.enabled, subscriptions.websocket.limits, subscriptions.websocket.connectionInitWaitTimeoutMs, and subscriptions.websocket.keepAliveMs.

  • @fluojs/core: Core DI and module system.
  • @fluojs/http: Underlying HTTP abstraction.
  • @fluojs/validation: Integrated DTO validation for GraphQL inputs.

Example Sources

  • packages/graphql/src/module.test.ts: Integration tests and usage examples for module registration, resolver execution, request-scoped containers, subscriptions, and guardrail defaults.
  • packages/graphql/field-resolver-rfc.md: Design notes for field-resolver patterns that are not part of the current runtime contract.

Keywords

fluo

FAQs

Package last updated on 01 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts