HTTP request handling, standalone server creation, and framework integration capabilities for Apollo Server.
Ready-to-use HTTP server implementation for Apollo Server with built-in CORS and body parsing.
/**
* Starts Apollo Server as a standalone HTTP server
* @param server - Apollo Server instance
* @param options - Server configuration and listen options
* @returns Promise resolving to server URL
*/
function startStandaloneServer(
server: ApolloServer<BaseContext>,
options?: StartStandaloneServerOptions<BaseContext> & {
listen?: ListenOptions;
}
): Promise<{ url: string }>;
/**
* Starts Apollo Server with custom context type
* @param server - Apollo Server instance with custom context
* @param options - Server configuration with required context function
* @returns Promise resolving to server URL
*/
function startStandaloneServer<TContext extends BaseContext>(
server: ApolloServer<TContext>,
options: WithRequired<StartStandaloneServerOptions<TContext>, 'context'> & {
listen?: ListenOptions;
}
): Promise<{ url: string }>;
/**
* Options for standalone server
*/
interface StartStandaloneServerOptions<TContext extends BaseContext> {
/** Context function receiving HTTP request/response */
context?: ContextFunction<
[StandaloneServerContextFunctionArgument],
TContext
>;
}
/**
* Context function argument for standalone server
*/
interface StandaloneServerContextFunctionArgument {
/** Node.js HTTP request object */
req: IncomingMessage;
/** Node.js HTTP response object */
res: ServerResponse;
}Types for handling HTTP-specific GraphQL requests and responses.
/**
* HTTP-specific GraphQL request information
*/
interface HTTPGraphQLRequest {
/** HTTP method (GET, POST, etc.) */
method: string;
/** Request headers */
headers: HeaderMap;
/** URL search parameters */
search: string;
/** Request body */
body: unknown;
}
/**
* HTTP response headers and status
*/
interface HTTPGraphQLHead {
/** HTTP status code */
status?: number;
/** Response headers */
headers: HeaderMap;
}
/**
* HTTP GraphQL response body
*/
type HTTPGraphQLResponseBody =
| { kind: 'complete'; string: string }
| { kind: 'chunked'; asyncIterator: AsyncIterator<string> };
/**
* Complete HTTP GraphQL response
*/
interface HTTPGraphQLResponse {
/** HTTP status code */
status?: number;
/** Response headers */
headers: HeaderMap;
/** Response body */
body: HTTPGraphQLResponseBody;
}Execute GraphQL requests through HTTP with complete request/response handling.
/**
* Executes a GraphQL request via HTTP protocol
* @param options - HTTP request and context configuration
* @returns Promise resolving to HTTP GraphQL response
*/
executeHTTPGraphQLRequest(options: {
httpGraphQLRequest: HTTPGraphQLRequest;
context: ContextThunk<TContext>;
}): Promise<HTTPGraphQLResponse>;Case-insensitive HTTP header management utility extending JavaScript Map.
/**
* Case-insensitive HTTP header map
* Extends Map<string, string> with case-insensitive key handling
*/
class HeaderMap extends Map<string, string> {
/**
* Sets a header value (key normalized to lowercase)
* @param key - Header name
* @param value - Header value
* @returns this for chaining
*/
set(key: string, value: string): this;
/**
* Gets a header value by name (case-insensitive)
* @param key - Header name
* @returns Header value or undefined
*/
get(key: string): string | undefined;
/**
* Deletes a header by name (case-insensitive)
* @param key - Header name
* @returns true if header existed and was deleted
*/
delete(key: string): boolean;
/**
* Checks if header exists by name (case-insensitive)
* @param key - Header name
* @returns true if header exists
*/
has(key: string): boolean;
}Types for managing GraphQL execution context in HTTP environments.
/**
* Base context type that all contexts must extend
*/
type BaseContext = {};
/**
* Function type for integration authors to create context
* @template TIntegrationSpecificArgs - Arguments provided by the integration
* @template TContext - The context type to return
*/
type ContextFunction<
TIntegrationSpecificArgs extends ReadonlyArray<any>,
TContext extends BaseContext
> = (...args: TIntegrationSpecificArgs) => Promise<TContext>;
/**
* Internal context thunk type
*/
type ContextThunk<TContext extends BaseContext> = () => Promise<TContext>;import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
const server = new ApolloServer({
typeDefs: `
type Query {
hello: String
}
`,
resolvers: {
Query: {
hello: () => "Hello world!",
},
},
});
// Start server on default port 4000
const { url } = await startStandaloneServer(server);
console.log(`๐ Server running at: ${url}`);import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
interface MyContext {
userId?: string;
userAgent: string;
}
const server = new ApolloServer<MyContext>({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
listen: { port: 8000 },
context: async ({ req, res }) => {
// Extract user ID from authorization header
const token = req.headers.authorization?.replace('Bearer ', '');
const userId = token ? await verifyToken(token) : undefined;
return {
userId,
userAgent: req.headers['user-agent'] || 'unknown',
};
},
});
console.log(`๐ Server running at: ${url}`);import { HeaderMap } from "@apollo/server";
// Create and manipulate headers
const headers = new HeaderMap();
headers.set('Content-Type', 'application/json');
headers.set('CACHE-CONTROL', 'no-cache'); // Case insensitive
console.log(headers.get('content-type')); // 'application/json'
console.log(headers.get('Cache-Control')); // 'no-cache'
console.log(headers.has('CONTENT-TYPE')); // true
// Iterate over headers
for (const [key, value] of headers) {
console.log(`${key}: ${value}`);
}// Example for Express integration (conceptual)
import express from 'express';
import { ApolloServer } from "@apollo/server";
interface ExpressContext {
req: express.Request;
res: express.Response;
user?: User;
}
const server = new ApolloServer<ExpressContext>({
typeDefs,
resolvers,
});
// In your Express route handler
app.post('/graphql', async (req, res) => {
const httpGraphQLResponse = await server.executeHTTPGraphQLRequest({
httpGraphQLRequest: {
method: req.method,
headers: new HeaderMap(Object.entries(req.headers) as [string, string][]),
search: req.url.split('?')[1] || '',
body: req.body,
},
context: async () => ({
req,
res,
user: req.user, // From authentication middleware
}),
});
// Handle response
res.status(httpGraphQLResponse.status || 200);
for (const [key, value] of httpGraphQLResponse.headers) {
res.setHeader(key, value);
}
if (httpGraphQLResponse.body.kind === 'complete') {
res.send(httpGraphQLResponse.body.string);
} else {
// Handle chunked response for subscriptions/streaming
for await (const chunk of httpGraphQLResponse.body.asyncIterator) {
res.write(chunk);
}
res.end();
}
});import http from 'http';
import { ApolloServer } from "@apollo/server";
import { HeaderMap } from "@apollo/server";
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
const httpServer = http.createServer(async (req, res) => {
if (req.url !== '/graphql') {
res.writeHead(404);
res.end('Not found');
return;
}
// Convert Node.js headers to HeaderMap
const headers = new HeaderMap();
for (const [key, value] of Object.entries(req.headers)) {
if (value !== undefined) {
headers.set(key, Array.isArray(value) ? value.join(', ') : value);
}
}
// Get request body
let body = '';
req.on('data', (chunk) => { body += chunk; });
req.on('end', async () => {
try {
const httpGraphQLResponse = await server.executeHTTPGraphQLRequest({
httpGraphQLRequest: {
method: req.method!.toUpperCase(),
headers,
search: new URL(req.url!, `http://${req.headers.host}`).search,
body: body ? JSON.parse(body) : undefined,
},
context: async () => ({}),
});
// Send response
res.writeHead(httpGraphQLResponse.status || 200,
Object.fromEntries(httpGraphQLResponse.headers));
if (httpGraphQLResponse.body.kind === 'complete') {
res.end(httpGraphQLResponse.body.string);
} else {
for await (const chunk of httpGraphQLResponse.body.asyncIterator) {
res.write(chunk);
}
res.end();
}
} catch (error) {
res.writeHead(500);
res.end('Internal server error');
}
});
});
httpServer.listen(4000, () => {
console.log('๐ Custom server running at http://localhost:4000/graphql');
});