109 lines
7.2 KiB
Markdown
109 lines
7.2 KiB
Markdown
# @suaveplan/api-plugin-graphql - GraphQL adapter plugin for @suaveplan/api — fluent SchemaBuilder / TypeBuilder for object/input/enum/interface/union types and queries/mutations/subscriptions, ResolverComposer with composable global + per-type middleware, requireRoles / validateArgs / createQueryExecutedMiddleware built-ins, typed graphqlEvents EventBus, defineGraphQLPlugin factory producing a GraphQLPluginDefinition compatible with the definePlugin pattern. 6 GRAPHQL.* error codes, Zod-validated boundary, OTel resolvers_executed_total + resolver_duration_ms instruments.
|
|
|
|
GraphQL description + resolver-composition layer for `@suaveplan/api`. Server-tier — runs in Bun and Node.
|
|
|
|
The package provides a typed, builder-driven way to declare GraphQL APIs without raw SDL. It does **not** ship a `graphql-js` executor — its output is a `GraphQLPluginDefinition` consumed by downstream tooling (a future `@suaveplan/api-plugin-graphql-executor`, or any third-party executor).
|
|
|
|
<!-- begin:auto-docs -->
|
|
## Documentation tree
|
|
|
|
- [error-codes](./src/error-codes/error-codes.md) — Defines the stable `GRAPHQL.*` error-code registry for `@suaveplan/api-plugin-graphql` and the `GraphQLError` class con…
|
|
- [error-codes](./src/error-codes/error-codes.md) — Defines the stable `GRAPHQL.*` error-code registry for `@suaveplan/api-plugin-graphql` and the `GraphQLError` class con…
|
|
- [otel](./src/otel/instruments.md) — Defines the OpenTelemetry instruments emitted from `createQueryExecutedMiddleware`. The middleware is the only producti…
|
|
- [instruments](./src/otel/instruments.md) — Defines the OpenTelemetry instruments emitted from `createQueryExecutedMiddleware`. The middleware is the only producti…
|
|
- [plugin](./src/plugin/plugin.md) — Declares `defineGraphQLPlugin(options)`, the factory that produces a `GraphQLPluginDefinition` consumable by the Suavep…
|
|
- [plugin](./src/plugin/plugin.md) — Declares `defineGraphQLPlugin(options)`, the factory that produces a `GraphQLPluginDefinition` consumable by the Suavep…
|
|
- [resolver](./src/resolver/resolver.md) — Implements `ResolverComposer` (the fluent builder for resolver maps), the two built-in middleware factories `requireRol…
|
|
- [resolver](./src/resolver/resolver.md) — Implements `ResolverComposer` (the fluent builder for resolver maps), the two built-in middleware factories `requireRol…
|
|
- [schema-builder](./src/schema-builder/schema-builder.md) — Declares `SchemaBuilder`, the fluent builder for GraphQL schema definitions. Consumers describe types, queries, mutatio…
|
|
- [schema-builder](./src/schema-builder/schema-builder.md) — Declares `SchemaBuilder`, the fluent builder for GraphQL schema definitions. Consumers describe types, queries, mutatio…
|
|
- [schemas](./src/schemas/options.md) — Defines `DefineGraphQLPluginOptionsSchema`, the Zod schema wired at the package boundary inside `defineGraphQLPlugin`.…
|
|
- [options](./src/schemas/options.md) — Defines `DefineGraphQLPluginOptionsSchema`, the Zod schema wired at the package boundary inside `defineGraphQLPlugin`.…
|
|
- [type-builder](./src/type-builder/type-builder.md) — Declares the `TypeBuilder` class — the inner builder `SchemaBuilder` hands to user-supplied callbacks when declaring ob…
|
|
- [type-builder](./src/type-builder/type-builder.md) — Declares the `TypeBuilder` class — the inner builder `SchemaBuilder` hands to user-supplied callbacks when declaring ob…
|
|
<!-- end:auto-docs -->
|
|
|
|
## What you get
|
|
|
|
- `defineGraphQLPlugin(options)` — typed factory producing a `GraphQLPluginDefinition` (name + merged config + lifecycle hooks + `getSchema()` / `getResolvers()`).
|
|
- `SchemaBuilder` — fluent builder for object / input / enum / interface / union types and queries / mutations / subscriptions.
|
|
- `TypeBuilder` — chainable field declarations consumed by `SchemaBuilder`.
|
|
- `ResolverComposer` — `use` / `useForType` / `addResolver` / `addResolvers` / `build`, with right-to-left middleware composition.
|
|
- `requireRoles(...roles)` — auth-check middleware. Throws `GraphQLError(UNAUTHENTICATED | INSUFFICIENT_ROLE)`.
|
|
- `validateArgs(validator)` — arg-validation middleware. Throws `GraphQLError(VALIDATION_FAILED)`.
|
|
- `graphqlEvents` — typed `EventBus<GraphQLEventMap>` for `graphql:query:executed`.
|
|
- `createQueryExecutedMiddleware(bus?)` — production observability middleware recording OTel instruments + emitting events.
|
|
- `GRAPHQL_CODES` + `GraphQLError` — 6 stable codes (`UNAUTHENTICATED`, `INSUFFICIENT_ROLE`, `VALIDATION_FAILED`, `INVALID_INPUT`, `TYPE_NOT_FOUND`, `DUPLICATE_RESOLVER`).
|
|
- OTel — `graphql.resolvers_executed_total{outcome}` counter and `graphql.resolver_duration_ms` histogram.
|
|
|
|
## Quick-start
|
|
|
|
```ts
|
|
import {
|
|
defineGraphQLPlugin,
|
|
ResolverComposer,
|
|
SchemaBuilder,
|
|
requireRoles,
|
|
validateArgs,
|
|
createQueryExecutedMiddleware,
|
|
graphqlEvents,
|
|
} from "@suaveplan/api-plugin-graphql";
|
|
|
|
const schema = new SchemaBuilder()
|
|
.addType("User", (t) =>
|
|
t.field("id", "ID", { required: true })
|
|
.field("email", "String", { required: true })
|
|
)
|
|
.addQuery("user", "User", {
|
|
args: [{ name: "id", type: "ID", required: true, isList: false }],
|
|
})
|
|
.addMutation("deleteUser", "Boolean", {
|
|
required: true,
|
|
args: [{ name: "id", type: "ID", required: true, isList: false }],
|
|
})
|
|
.build();
|
|
|
|
const resolvers = new ResolverComposer()
|
|
.useForType("Query", createQueryExecutedMiddleware())
|
|
.useForType("Mutation", createQueryExecutedMiddleware())
|
|
.useForType("Mutation", requireRoles("admin"))
|
|
.useForType(
|
|
"Mutation",
|
|
validateArgs((a) => (typeof a.id === "string" ? null : "id required"))
|
|
)
|
|
.addResolver("Query", "user", (_p, args) => ({ id: args.id, email: "x@y" }))
|
|
.addResolver("Mutation", "deleteUser", () => true)
|
|
.build();
|
|
|
|
graphqlEvents.on("graphql:query:executed", (e) => {
|
|
console.log(`${e.operationType}.${e.operationName} ${e.durationMs}ms`);
|
|
});
|
|
|
|
const definition = defineGraphQLPlugin({
|
|
name: "users-gql",
|
|
version: "0.1.0",
|
|
schema,
|
|
resolvers,
|
|
});
|
|
```
|
|
|
|
## Modules
|
|
|
|
- [`error-codes/error-codes.md`](src/error-codes/error-codes.md) — `GRAPHQL_CODES`, `GraphQLError`.
|
|
- [`otel/instruments.md`](src/otel/instruments.md) — OTel instruments.
|
|
- [`plugin/plugin.md`](src/plugin/plugin.md) — `defineGraphQLPlugin`.
|
|
- [`resolver/resolver.md`](src/resolver/resolver.md) — `ResolverComposer`, `requireRoles`, `validateArgs`, `createQueryExecutedMiddleware`, `graphqlEvents`.
|
|
- [`schema-builder/schema-builder.md`](src/schema-builder/schema-builder.md) — `SchemaBuilder`.
|
|
- [`schemas/options.md`](src/schemas/options.md) — `DefineGraphQLPluginOptionsSchema`.
|
|
- [`type-builder/type-builder.md`](src/type-builder/type-builder.md) — `TypeBuilder`.
|
|
- [`types/graphql.types.md`](src/types/graphql.types.md) — full type surface.
|
|
|
|
## Scope
|
|
|
|
This package is functional-parity with upstream `@suaveplan/api-plugin-graphql` (suaveplan main, v1.0.4) plus hardening (typed errors, Zod boundary, OTel). Live execution (`graphql-js`), federation, persisted queries, subscriptions transport, SDL emission, and schema-registry publishing are **out of scope** for this release and are enumerated in `enterprise/api-plugin-graphql.md` §3 as future enterprise upgrades.
|
|
|
|
## License
|
|
|
|
MIT.
|
|
|