Type-safe context system with initial context setup, user context extension, comprehensive TypeScript support for server and user context types, and utility type definitions.
Core context interface provided to all GraphQL operations containing request information and parameters.
/**
* Initial context interface available to all GraphQL operations
*/
interface YogaInitialContext extends ServerAdapterInitialContext {
/** Parsed GraphQL parameters from the request */
params: GraphQLParams;
/** Original HTTP request object */
request: Request;
}Base context interface from the server adapter providing core server functionality.
/**
* Server adapter initial context (from @whatwg-node/server)
*/
interface ServerAdapterInitialContext {
/** Server adapter request object */
request: Request;
/** Server adapter fetch API */
fetch: typeof fetch;
/** Server adapter URL utilities */
url: URL;
/** Environment variables */
env?: Record<string, string>;
/** Execution context for serverless environments */
executionContext?: any;
/** Additional server context properties */
[key: string]: any;
}Type definitions for Cross-Origin Resource Sharing configuration.
/**
* CORS configuration options
*/
type CORSOptions =
| {
/** Allowed origins - string, array of strings, or function */
origin?: string[] | string | ((origin: string) => boolean);
/** Allowed HTTP methods */
methods?: string[];
/** Allowed request headers */
allowedHeaders?: string[];
/** Headers exposed to the client */
exposedHeaders?: string[];
/** Allow credentials in CORS requests */
credentials?: boolean;
/** Preflight response cache duration in seconds */
maxAge?: number;
/** Enable CORS preflight for simple requests */
preflightContinue?: boolean;
/** Provide options to next handler */
optionsSuccessStatus?: number;
}
| false; // Disable CORS entirelyType definitions for the Fetch API implementation used by GraphQL Yoga.
/**
* Fetch API implementation type (from @whatwg-node/fetch)
*/
type FetchAPI = ReturnType<typeof createFetch>;
/**
* Fetch event interface for service worker environments
*/
interface FetchEvent extends Event {
/** The fetch request */
request: Request;
/** Respond with a response or promise */
respondWith(response: Response | Promise<Response>): void;
/** Wait until promise resolves */
waitUntil(promise: Promise<any>): void;
}General utility types used throughout the GraphQL Yoga API.
/**
* Type that can be a single value or an array
*/
type MaybeArray<T> = T | T[];
/**
* Type that can be a value or a promise
*/
type PromiseOrValue<T> = T | Promise<T>;
/**
* Optional type utility
*/
type Optional<T> = T | undefined;
/**
* Maybe type utility (includes null)
*/
type Maybe<T> = T | null | undefined;
/**
* Spread utility type for object merging
*/
type Spread<T> = T extends (...args: any[]) => any
? T
: T extends ReadonlyArray<any>
? { [K in keyof T]: T[K] }
: T extends object
? { [K in keyof T]: T[K] }
: T;
/**
* Async iterable iterator or direct value
*/
type AsyncIterableIteratorOrValue<T> = AsyncIterableIterator<T> | T;Interface for HTTP-specific extensions in GraphQL responses.
/**
* HTTP-specific extensions for GraphQL responses
*/
interface GraphQLHTTPExtensions {
/** HTTP status code for the response */
status?: number;
/** Additional HTTP headers to include */
headers?: Record<string, string>;
/** HTTP status text */
statusText?: string;
}Type definitions for context creation and extension.
/**
* Context factory function type for creating user context
*/
type ContextFactory<TServerContext, TUserContext> = (
initialContext: YogaInitialContext & TServerContext
) => PromiseOrValue<TUserContext>;
/**
* Context extension function type
*/
type ContextExtension<TContext, TExtension> = (
context: TContext
) => PromiseOrValue<TExtension>;Types for resource disposal and cleanup in server environments.
/**
* Disposal symbols for resource cleanup (from @whatwg-node/server)
*/
declare const DisposableSymbols: {
dispose: symbol;
asyncDispose: symbol;
};
/**
* Disposable resource interface
*/
interface Disposable {
[DisposableSymbols.dispose](): void;
}
/**
* Async disposable resource interface
*/
interface AsyncDisposable {
[DisposableSymbols.asyncDispose](): Promise<void>;
}Usage Examples:
import {
createYoga,
YogaInitialContext,
CORSOptions,
MaybeArray,
PromiseOrValue
} from 'graphql-yoga';
// Basic context setup
interface MyServerContext {
database: Database;
logger: Logger;
}
interface MyUserContext {
user?: User;
permissions: string[];
}
const yoga = createYoga<MyServerContext, MyUserContext>({
schema: mySchema,
context: async ({ request, params }) => {
// Extract user from request
const token = request.headers.get('authorization');
const user = token ? await validateToken(token) : null;
return {
user,
permissions: user ? await getUserPermissions(user.id) : []
};
}
});
// Advanced context with server context
const advancedYoga = createYoga<MyServerContext, MyUserContext>({
schema: mySchema,
context: async (initialContext) => {
const { request, params } = initialContext;
const { database, logger } = initialContext; // Server context
logger.info('Processing request', {
operation: params.operationName,
userAgent: request.headers.get('user-agent')
});
// Authenticate user
const authHeader = request.headers.get('authorization');
let user: User | undefined;
if (authHeader?.startsWith('Bearer ')) {
const token = authHeader.slice(7);
user = await database.users.findByToken(token);
}
// Get user permissions
const permissions = user
? await database.permissions.findByUserId(user.id)
: [];
return { user, permissions };
}
});
// CORS configuration examples
const corsOptions: CORSOptions = {
origin: ['http://localhost:3000', 'https://myapp.com'],
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Request-ID'],
credentials: true,
maxAge: 86400 // 24 hours
};
const corsYoga = createYoga({
schema: mySchema,
cors: corsOptions
});
// Dynamic CORS configuration
const dynamicCorsYoga = createYoga({
schema: mySchema,
cors: {
origin: (origin) => {
// Allow all localhost origins in development
if (process.env.NODE_ENV === 'development') {
return origin.includes('localhost');
}
// Strict whitelist in production
return ['https://myapp.com', 'https://admin.myapp.com'].includes(origin);
},
credentials: true
}
});
// Context with type utilities
function createContextFactory<T>(): ContextFactory<{}, T> {
return (initialContext): PromiseOrValue<T> => {
// Implementation
return {} as T;
};
}
// Using utility types in resolvers
const resolvers = {
Query: {
users: (): MaybeArray<User> => {
// Can return single user or array
return [{ id: '1', name: 'Alice' }];
},
asyncData: async (): PromiseOrValue<string> => {
// Can return value directly or promise
return 'data';
},
optionalUser: (): Optional<User> => {
// May return undefined
return undefined;
}
}
};
// Context extension plugin
function useContextExtension<T>(extension: T): Plugin {
return {
onParams({ setParams, params }) {
setParams({
...params,
extensions: {
...params.extensions,
contextExtension: extension
}
});
}
};
}
// Multi-tenant context
interface TenantContext {
tenantId: string;
tenantConfig: TenantConfig;
}
const multiTenantYoga = createYoga<{}, TenantContext>({
schema: mySchema,
context: async ({ request }) => {
// Extract tenant from subdomain or header
const host = request.headers.get('host') || '';
const tenantId = host.split('.')[0];
if (!tenantId) {
throw new Error('Tenant not specified');
}
const tenantConfig = await getTenantConfig(tenantId);
return {
tenantId,
tenantConfig
};
}
});
// Request context enrichment
function enrichContext<T extends YogaInitialContext>(
baseContext: T
): T & { enriched: true } {
return {
...baseContext,
enriched: true
};
}
// Context validation
function validateContext<T>(context: T): asserts context is T {
if (!context) {
throw new Error('Context is required');
}
}
// Context with cleanup resources
interface ResourceContext {
database: Database;
cache: Cache;
}
class DatabaseConnection implements AsyncDisposable {
async [DisposableSymbols.asyncDispose](): Promise<void> {
await this.close();
}
async close(): Promise<void> {
// Cleanup database connection
}
}
const resourceYoga = createYoga<ResourceContext, {}>({
schema: mySchema,
context: async () => {
const database = new DatabaseConnection();
const cache = new CacheConnection();
return { database, cache };
}
});
// Type-safe context access in resolvers
const typedResolvers = {
Query: {
me: (
_: any,
__: any,
context: YogaInitialContext & MyUserContext
): User | null => {
// TypeScript knows context has user and permissions
return context.user || null;
},
secureData: (
_: any,
__: any,
context: YogaInitialContext & MyUserContext
): string => {
if (!context.user) {
throw new Error('Authentication required');
}
if (!context.permissions.includes('READ_SECURE_DATA')) {
throw new Error('Insufficient permissions');
}
return 'Secret data';
}
}
};