Skip to content

Server API

Effect GraphQL provides server integration APIs in @effect-gql/core for HTTP routing and WebSocket subscriptions.

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:

NameTypeDescription
schemaGraphQLSchemaBuilt GraphQL schema
layerLayer<R>Service layer for resolvers
configGraphQLRouterConfigInputOptional 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
})

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 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
}

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:

VariableTypeDefaultDescription
GRAPHQL_PATHstring/graphqlGraphQL endpoint path
GRAPHIQL_ENABLEDbooleanfalseEnable GraphiQL
GRAPHIQL_PATHstring/graphiqlGraphiQL UI path
GRAPHIQL_ENDPOINTstring(path)GraphQL URL for GraphiQL

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:

NameTypeDescription
schemaGraphQLSchemaGraphQL schema with subscriptions
layerLayer<R>Service layer for resolvers
optionsGraphQLWSOptions<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 }
})
})

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>
}

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
}

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
}

The @effect-gql/node package provides Node.js-specific server utilities.

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>
): void

Options:

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 subscriptions
serve(router, serviceLayer, {
port: 4000,
onStart: (url) => console.log(`Server at ${url}`)
})
// With subscriptions
serve(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)
// Cleanup
process.on("SIGTERM", async () => {
await close()
httpServer.close()
})

Convert a ws WebSocket to an EffectWebSocket.

import { toEffectWebSocket } from "@effect-gql/node"
import { WebSocket } from "ws"
function toEffectWebSocket(ws: WebSocket): EffectWebSocket

Example:

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 type for WebSocket operations.

import { WebSocketError } from "@effect-gql/core"
class WebSocketError extends Data.TaggedError("WebSocketError")<{
readonly cause: unknown
}>

WebSocket close event information.

interface CloseEvent {
readonly code: number
readonly reason: string
}

Generate HTML for GraphiQL IDE.

import { graphiqlHtml } from "@effect-gql/core"
function graphiqlHtml(endpoint: string): string

The 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