Server API
Effect GraphQL provides server integration APIs in @effect-gql/core for HTTP routing and WebSocket subscriptions.
HTTP Router
Section titled “HTTP Router”makeGraphQLRouter(schema, layer, config)
Section titled “makeGraphQLRouter(schema, layer, config)”Create an HttpRouter configured for GraphQL.
import { makeGraphQLRouter } from "@effect-gql/core"
function makeGraphQLRouter<R>( schema: GraphQLSchema, layer: Layer.Layer<R>, config?: GraphQLRouterConfigInput): HttpRouter.HttpRouter<never, never>Parameters:
| Name | Type | Description |
|---|---|---|
schema | GraphQLSchema | Built GraphQL schema |
layer | Layer<R> | Service layer for resolvers |
config | GraphQLRouterConfigInput | Optional configuration |
Example:
import { makeGraphQLRouter } from "@effect-gql/core"import { Layer } from "effect"
const schema = builder.buildSchema()
const router = makeGraphQLRouter(schema, serviceLayer, { path: "/graphql", graphiql: true})toRouter(builder, layer, config)
Section titled “toRouter(builder, layer, config)”Convert a GraphQLSchemaBuilder directly to an HttpRouter.
import { toRouter } from "@effect-gql/core"
function toRouter<R, R2>( builder: GraphQLSchemaBuilder<R>, layer: Layer.Layer<R2>, config?: GraphQLRouterConfigInput): HttpRouter.HttpRouter<never, never>Example:
import { GraphQLSchemaBuilder, query, toRouter } from "@effect-gql/core"
const builder = GraphQLSchemaBuilder.empty.pipe( query("hello", { type: S.String, resolve: () => Effect.succeed("world") }))
const router = toRouter(builder, Layer.empty, { graphiql: true })Configuration
Section titled “Configuration”GraphQLRouterConfigInput
Section titled “GraphQLRouterConfigInput”Configuration options for the GraphQL router.
interface GraphQLRouterConfigInput { /** Path for GraphQL endpoint (default: "/graphql") */ readonly path?: string
/** GraphiQL configuration */ readonly graphiql?: boolean | Partial<GraphiQLConfig>}
interface GraphiQLConfig { /** Path where GraphiQL UI is served (default: "/graphiql") */ readonly path: string /** URL where GraphiQL sends requests (default: same as graphql path) */ readonly endpoint: string}GraphQLRouterConfigFromEnv
Section titled “GraphQLRouterConfigFromEnv”Load configuration from environment variables.
import { GraphQLRouterConfigFromEnv } from "@effect-gql/core"import { Effect } from "effect"
const program = Effect.gen(function* () { const config = yield* GraphQLRouterConfigFromEnv const router = makeGraphQLRouter(schema, layer, config)})Environment Variables:
| Variable | Type | Default | Description |
|---|---|---|---|
GRAPHQL_PATH | string | /graphql | GraphQL endpoint path |
GRAPHIQL_ENABLED | boolean | false | Enable GraphiQL |
GRAPHIQL_PATH | string | /graphiql | GraphiQL UI path |
GRAPHIQL_ENDPOINT | string | (path) | GraphQL URL for GraphiQL |
WebSocket Handler
Section titled “WebSocket Handler”makeGraphQLWSHandler(schema, layer, options)
Section titled “makeGraphQLWSHandler(schema, layer, options)”Create a WebSocket handler for GraphQL subscriptions.
import { makeGraphQLWSHandler } from "@effect-gql/core"
function makeGraphQLWSHandler<R>( schema: GraphQLSchema, layer: Layer.Layer<R>, options?: GraphQLWSOptions<R>): (socket: EffectWebSocket) => Effect.Effect<void, never, never>Parameters:
| Name | Type | Description |
|---|---|---|
schema | GraphQLSchema | GraphQL schema with subscriptions |
layer | Layer<R> | Service layer for resolvers |
options | GraphQLWSOptions<R> | Lifecycle hooks |
Example:
import { makeGraphQLWSHandler } from "@effect-gql/core"
const handler = makeGraphQLWSHandler(schema, serviceLayer, { onConnect: (params) => Effect.gen(function* () { const user = yield* AuthService.validateToken(params.authToken) return { user } })})GraphQLWSOptions<R>
Section titled “GraphQLWSOptions<R>”Lifecycle hooks for WebSocket connections.
interface GraphQLWSOptions<R> { /** Called when client connects */ readonly onConnect?: ( params: Record<string, unknown> ) => Effect.Effect<boolean | Record<string, unknown>, unknown, R>
/** Called when client disconnects */ readonly onDisconnect?: ( ctx: ConnectionContext<R> ) => Effect.Effect<void, never, R>
/** Called for each subscription */ readonly onSubscribe?: ( ctx: ConnectionContext<R>, message: SubscribeMessage ) => Effect.Effect<void, unknown, R>
/** Called when subscription completes */ readonly onComplete?: ( ctx: ConnectionContext<R>, message: CompleteMessage ) => Effect.Effect<void, never, R>
/** Called on subscription error */ readonly onError?: ( ctx: ConnectionContext<R>, error: unknown ) => Effect.Effect<void, never, R>}ConnectionContext<R>
Section titled “ConnectionContext<R>”Context available during WebSocket connection.
interface ConnectionContext<R> { /** Effect runtime for this connection */ readonly runtime: Runtime.Runtime<R>
/** Client-provided connection parameters */ readonly connectionParams: Record<string, unknown>
/** The WebSocket instance */ readonly socket: EffectWebSocket}EffectWebSocket
Section titled “EffectWebSocket”Platform-neutral WebSocket interface.
interface EffectWebSocket { /** Send a message */ readonly send: (data: string) => Effect.Effect<void, WebSocketError>
/** Close the connection */ readonly close: (code?: number, reason?: string) => Effect.Effect<void, WebSocketError>
/** Stream of incoming messages */ readonly messages: Stream.Stream<string, WebSocketError>
/** Effect that completes when connection closes */ readonly closed: Effect.Effect<CloseEvent, WebSocketError>
/** WebSocket subprotocol */ readonly protocol: string}Node.js Package
Section titled “Node.js Package”The @effect-gql/node package provides Node.js-specific server utilities.
serve(router, layer, options)
Section titled “serve(router, layer, options)”Start a Node.js HTTP server.
import { serve } from "@effect-gql/node"
function serve<E, R, RE>( router: HttpRouter.HttpRouter<E, R>, layer: Layer.Layer<R, RE>, options?: ServeOptions<R>): voidOptions:
interface ServeOptions<R> { /** Port to listen on (default: 4000) */ readonly port?: number
/** Hostname to bind to (default: "0.0.0.0") */ readonly host?: string
/** Callback when server starts */ readonly onStart?: (url: string) => void
/** WebSocket subscriptions config */ readonly subscriptions?: SubscriptionsConfig<R>}
interface SubscriptionsConfig<R> extends GraphQLWSOptions<R> { /** The GraphQL schema (required) */ readonly schema: GraphQLSchema
/** WebSocket path (default: "/graphql") */ readonly path?: string}Example:
import { toRouter } from "@effect-gql/core"import { serve } from "@effect-gql/node"
const router = toRouter(builder, serviceLayer, { graphiql: true })
// Without subscriptionsserve(router, serviceLayer, { port: 4000, onStart: (url) => console.log(`Server at ${url}`)})
// With subscriptionsserve(router, serviceLayer, { port: 4000, subscriptions: { schema: builder.buildSchema(), onConnect: (params) => validateAuth(params) }})createGraphQLWSServer(schema, layer, options)
Section titled “createGraphQLWSServer(schema, layer, options)”Create a WebSocket server for manual HTTP server integration.
import { createGraphQLWSServer } from "@effect-gql/node"
function createGraphQLWSServer<R>( schema: GraphQLSchema, layer: Layer.Layer<R>, options?: NodeWSOptions<R>): { wss: WebSocketServer handleUpgrade: (request, socket, head) => void close: () => Promise<void>}Example:
import { createServer } from "node:http"import { createGraphQLWSServer } from "@effect-gql/node"
const httpServer = createServer(httpHandler)
const { handleUpgrade, close } = createGraphQLWSServer(schema, serviceLayer, { path: "/graphql"})
httpServer.on("upgrade", handleUpgrade)httpServer.listen(4000)attachWebSocketToServer(server, schema, layer, options)
Section titled “attachWebSocketToServer(server, schema, layer, options)”Attach WebSocket support to an existing HTTP server.
import { attachWebSocketToServer } from "@effect-gql/node"
function attachWebSocketToServer<R>( server: Server, schema: GraphQLSchema, layer: Layer.Layer<R>, options?: NodeWSOptions<R>): { close: () => Promise<void> }Example:
import { createServer } from "node:http"import { attachWebSocketToServer } from "@effect-gql/node"
const httpServer = createServer(httpHandler)
const { close } = attachWebSocketToServer(httpServer, schema, serviceLayer)
httpServer.listen(4000)
// Cleanupprocess.on("SIGTERM", async () => { await close() httpServer.close()})toEffectWebSocket(ws)
Section titled “toEffectWebSocket(ws)”Convert a ws WebSocket to an EffectWebSocket.
import { toEffectWebSocket } from "@effect-gql/node"import { WebSocket } from "ws"
function toEffectWebSocket(ws: WebSocket): EffectWebSocketExample:
import { WebSocketServer } from "ws"import { toEffectWebSocket } from "@effect-gql/node"import { makeGraphQLWSHandler } from "@effect-gql/core"
const handler = makeGraphQLWSHandler(schema, layer)const wss = new WebSocketServer({ port: 4000 })
wss.on("connection", (ws) => { const effectSocket = toEffectWebSocket(ws) Effect.runPromise(handler(effectSocket))})Error Types
Section titled “Error Types”WebSocketError
Section titled “WebSocketError”Error type for WebSocket operations.
import { WebSocketError } from "@effect-gql/core"
class WebSocketError extends Data.TaggedError("WebSocketError")<{ readonly cause: unknown}>CloseEvent
Section titled “CloseEvent”WebSocket close event information.
interface CloseEvent { readonly code: number readonly reason: string}GraphiQL
Section titled “GraphiQL”graphiqlHtml(endpoint)
Section titled “graphiqlHtml(endpoint)”Generate HTML for GraphiQL IDE.
import { graphiqlHtml } from "@effect-gql/core"
function graphiqlHtml(endpoint: string): stringThe generated HTML loads GraphiQL from CDN and configures it to send requests to the specified endpoint.
Example:
import { graphiqlHtml } from "@effect-gql/core"
const html = graphiqlHtml("/graphql")// Returns full HTML page with GraphiQL configured