@mercuriusjs/gateway
Version:
A plugin for mercurius federation
203 lines (180 loc) • 7.67 kB
TypeScript
import { FastifyInstance, FastifyReply } from 'fastify'
import { MercuriusContext, MercuriusPlugin, MercuriusOptions, PreExecutionHookResponse } from 'mercurius'
import { IncomingHttpHeaders, OutgoingHttpHeaders } from "http"
import {
DocumentNode,
GraphQLSchema,
ExecutionResult,
} from "graphql";
interface ServiceConfig {
setSchema: (schema: string) => ServiceConfig;
}
interface Gateway {
refresh: (isRetry?: boolean) => Promise<GraphQLSchema | null>;
serviceMap: Record<string, ServiceConfig>;
/**
* `preGatewayExecution` is the hook to be executed in the GraphQL gateway request lifecycle.
* The previous hook was `preExecution`, the next hook will be `onResolution`.
* Notice: in the `preGatewayExecution` hook, you can modify the following items by returning them in the hook definition:
* - `document`
* - `errors`
* Each hook definition will trigger multiple times in a single request just before executing remote GraphQL queries on the federated services.
*/
addHook<TContext = MercuriusContext, TError extends Error = Error>(name: 'preGatewayExecution', hook: preGatewayExecutionHookHandler<TContext, TError>): void;
/**
* `preGatewaySubscriptionExecution` is the hook to be executed in the GraphQL gateway subscription lifecycle.
* The previous hook was `preSubscriptionExecution`, the next hook will be `onSubscriptionResolution`.
*/
addHook<TContext = MercuriusContext>(name: 'preGatewaySubscriptionExecution', hook: preGatewaySubscriptionExecutionHookHandler<TContext>): void;
/**
* `onGatewayReplaceSchema` is an application lifecycle hook. When the Gateway service obtains new versions of federated schemas within a defined polling interval, the `onGatewayReplaceSchema` hook will be triggered every time a new schema is built. It is called just before the old schema is replaced with the new one.
* This hook will only be triggered in gateway mode. It has the following parameters:
* - `instance` - The gateway server `FastifyInstance` (this contains the old schema).
* - `schema` - The new schema that has been built from the gateway refresh.
*/
addHook(name: 'onGatewayReplaceSchema', hook: onGatewayReplaceSchemaHookHandler): void;
}
declare module "fastify" {
interface FastifyInstance {
/**
* GraphQL plugin
*/
graphqlGateway: Gateway
}
interface FastifyReply {
/**
* @param source GraphQL query string
* @param context request context
* @param variables request variables which will get passed to the executor
* @param operationName specify which operation will be run
*/
graphql<
TData extends Record<string, any> = Record<string, any>,
TVariables extends Record<string, any> = Record<string, any>
>(
source: string,
context?: Record<string, any>,
variables?: TVariables,
operationName?: string
): Promise<ExecutionResult<TData>>;
}
}
/**
* Federated GraphQL Service metadata
*/
export interface MercuriusServiceMetadata {
name: string;
}
export interface Collectors {
collectHeaders?: boolean;
collectStatutsCodes?: boolean;
collectExtensions?: boolean;
}
interface WsConnectionParams {
connectionInitPayload?:
| (() => Record<string, any> | Promise<Record<string, any>>)
| Record<string, any>;
reconnect?: boolean;
maxReconnectAttempts?: number;
connectionCallback?: () => void;
failedConnectionCallback?: (err: { message: string }) => void | Promise<void>;
failedReconnectCallback?: () => void;
rewriteConnectionInitPayload?: <TContext extends MercuriusContext = MercuriusContext>(payload: Record<string, any> | undefined, context: TContext) => Record<string, any>;
}
export interface MercuriusGatewayService {
name: string;
url: string | string[];
schema?: string;
wsUrl?: string;
mandatory?: boolean;
initHeaders?:
| (() => OutgoingHttpHeaders | Promise<OutgoingHttpHeaders>)
| OutgoingHttpHeaders;
rewriteHeaders?: <TContext extends MercuriusContext = MercuriusContext>(
headers: IncomingHttpHeaders,
context: TContext
) => OutgoingHttpHeaders | Promise<OutgoingHttpHeaders>;
connections?: number;
bodyTimeout?: number;
headersTimeout?: number;
maxHeaderSize?: number;
keepAlive?: number;
keepAliveMaxTimeout?: number;
rejectUnauthorized?: boolean;
wsConnectionParams?:
| (() => WsConnectionParams | Promise<WsConnectionParams>)
| WsConnectionParams;
setResponseHeaders?: (reply: FastifyReply) => void;
collectors?: Collectors;
allowBatchedQueries?: boolean;
}
export interface MercuriusGatewayOptions {
gateway: {
services: Array<MercuriusGatewayService> | (() => Promise<Array<MercuriusGatewayService>>);
pollingInterval?: number;
errorHandler?(error: Error, service: MercuriusGatewayService): void;
retryServicesCount?: number;
retryServicesInterval?: number;
};
}
type MercuriusFederationOptions = MercuriusOptions & MercuriusGatewayOptions
declare const mercuriusGatewayPlugin: (
instance: FastifyInstance,
opts: MercuriusFederationOptions
) => void
export default mercuriusGatewayPlugin;
// ------------------------
// Request Lifecycle hooks
// ------------------------
/**
* `preGatewayExecution` is the hook to be executed in the GraphQL gateway request lifecycle.
* The previous hook was `preExecution`, the next hook will be `onResolution`.
* Notice: in the `preGatewayExecution` hook, you can modify the following items by returning them in the hook definition:
* - `document`
* - `errors`
* Each hook definition will trigger multiple times in a single request just before executing remote GraphQL queries on the federated services.
*
* Because it is a gateway hook, this hook contains service metadata in the `service` parameter:
* - `name`: service name
*/
export interface preGatewayExecutionHookHandler<TContext = MercuriusContext, TError extends Error = Error> {
(
schema: GraphQLSchema,
source: DocumentNode,
context: TContext,
service: MercuriusServiceMetadata
): Promise<PreExecutionHookResponse<TError> | void> | PreExecutionHookResponse<TError> | void;
}
// -----------------------------
// Subscription Lifecycle hooks
// -----------------------------
/**
* `preGatewaySubscriptionExecution` is the hook to be executed in the GraphQL gateway subscription lifecycle.
* The previous hook was `preSubscriptionExecution`, the next hook will be `onSubscriptionResolution`.
*
* Because it is a gateway hook, this hook contains service metadata in the `service` parameter:
* - `name`: service name
*/
export interface preGatewaySubscriptionExecutionHookHandler<TContext = MercuriusContext> {
(
schema: GraphQLSchema,
source: DocumentNode,
context: TContext,
service: MercuriusServiceMetadata
): Promise<void> | void;
}
// ----------------------------
// Application Lifecycle hooks
// ----------------------------
/**
* `onGatewayReplaceSchema` is an application lifecycle hook. When the Gateway service obtains new versions of federated schemas within a defined polling interval, the `onGatewayReplaceSchema` hook will be triggered every time a new schema is built. It is called just before the old schema is replaced with the new one.
* This hook will only be triggered in gateway mode. It has the following parameters:
* - `instance` - The gateway server `FastifyInstance` (this contains the old schema).
* - `schema` - The new schema that has been built from the gateway refresh.
*/
export interface onGatewayReplaceSchemaHookHandler {
(
instance: FastifyInstance,
schema: GraphQLSchema
): Promise<void> | void;
}