first commit
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# `engine/apollo-engine` — `ApolloGraphqlEngine`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`ApolloGraphqlEngine` is the concrete Apollo Server implementation of
|
||||
the `@suaveplan/api-graphql` engine contract. It owns the Apollo
|
||||
Server instance, the merged executable schema, the persisted-query
|
||||
manifest plumbing, the request-time depth and complexity guards, and
|
||||
the OTel instrument emission. The factory `createApolloGraphqlEngine`
|
||||
hands out fresh instances; the class is `new`-able for tests and
|
||||
power users that want subclass overrides.
|
||||
|
||||
Every operation pivots on three lifecycle calls: `buildSchema` once
|
||||
at boot (or on hot reload), `executeQuery` per request, `dispose` at
|
||||
shutdown. Schema rebuild gracefully tears down the prior Apollo
|
||||
instance only when its startup has completed — a half-started server
|
||||
is left alone, which is safe because the new server replaces the
|
||||
slot.
|
||||
|
||||
## Features
|
||||
|
||||
- Implements every `GraphqlEngine` method — `buildSchema`,
|
||||
`executeQuery`, `executeSubscription`, `dispose`.
|
||||
- Pluggable `instruments`, `persistedQueries`, `apolloPlugins`
|
||||
dependencies — sane defaults, full override.
|
||||
- Depth + complexity guards run BEFORE Apollo sees the document so
|
||||
the engine rejects pathological queries cheaply.
|
||||
- `requestTimeoutMs` enforced via a race against a `setTimeout`-
|
||||
driven rejection — the timer is `unref`'d so it never holds the
|
||||
event loop open.
|
||||
- `attachResolvers` resolves SDL-declared fields against the
|
||||
registry's resolver maps; unknown types and unknown fields are
|
||||
silently skipped so plugin authors can register superset maps
|
||||
without runtime breakage.
|
||||
- Introspection denial layered above Apollo's
|
||||
`introspection: false` flag so the engine raises a typed error
|
||||
before Apollo even validates the document.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createGraphqlRegistry } from "@suaveplan/api-graphql";
|
||||
import { createApolloGraphqlEngine } from "@suaveplan/api-graphql-apollo";
|
||||
|
||||
const engine = createApolloGraphqlEngine();
|
||||
const registry = createGraphqlRegistry();
|
||||
registry.addTypes("type Query { ping: String! }");
|
||||
registry.addResolvers({ Query: { ping: () => "pong" } });
|
||||
engine.buildSchema(registry);
|
||||
const result = await engine.executeQuery(
|
||||
{ query: "{ ping }" },
|
||||
requestContext
|
||||
);
|
||||
await engine.dispose();
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Wire persisted queries, custom instruments, a 5-second timeout, and a
|
||||
custom Apollo plugin for cache control:
|
||||
|
||||
```ts
|
||||
import { createApolloGraphqlEngine } from "@suaveplan/api-graphql-apollo";
|
||||
import { createInstruments } from "@suaveplan/api-graphql-apollo/instruments";
|
||||
import { createPersistedQueryManifest } from "@suaveplan/api-graphql-apollo/persisted-queries";
|
||||
|
||||
const instruments = createInstruments();
|
||||
const persistedQueries = createPersistedQueryManifest([
|
||||
["abc123", "{ ping }"],
|
||||
]);
|
||||
const engine = createApolloGraphqlEngine({
|
||||
instruments,
|
||||
persistedQueries,
|
||||
apolloPlugins: [cacheControlPlugin],
|
||||
options: { requestTimeoutMs: 5000, maxQueryDepth: 12 },
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `class ApolloGraphqlEngine<Caps> implements GraphqlEngine<Caps>`.
|
||||
- `constructor(args?: CreateApolloGraphqlEngineArgs)`
|
||||
- `buildSchema(registry): MergedSchema`
|
||||
- `executeQuery(req, ctx): Promise<GraphqlResponse>`
|
||||
- `executeSubscription(req, ctx): AsyncIterable<GraphqlResponse>`
|
||||
- `dispose(): Promise<void>`
|
||||
- `sdl(): string | null`
|
||||
- `createApolloGraphqlEngine(args?): ApolloGraphqlEngine`.
|
||||
- `raceWithTimeout<T>(p, ms): Promise<T>` — exported for unit testing.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests`
|
||||
was rejected in favour of an explicit `start()` Promise because the
|
||||
former turns a startup failure into per-request rejections we cannot
|
||||
discriminate cleanly. The current implementation awaits the start
|
||||
promise inside `executeQuery` and again inside `dispose` so a failed
|
||||
start never leaves the engine in a half-stopped state. The
|
||||
`raceWithTimeout` helper is exported so a focused unit test can
|
||||
exercise both the resolve and reject branches without standing up an
|
||||
Apollo Server.
|
||||
Reference in New Issue
Block a user