@nxara/olio-http 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -216
- package/dist/node.d.ts +3 -3
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +26 -3
- package/dist/node.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,224 +1,11 @@
|
|
|
1
1
|
# @nxara/olio-http
|
|
2
2
|
|
|
3
|
-
Serve an olio app over HTTP,
|
|
3
|
+
Serve an olio app over HTTP, from any framework, on graphql-http: Fetch and Node adapters with `context`, error masking and per-operation cleanup.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
6
|
bun add @nxara/olio-http graphql@16
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**[Read the docs](https://olio.nxara.dev/reference/http/)**
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
| Import | For |
|
|
14
|
-
| --- | --- |
|
|
15
|
-
| `@nxara/olio-http/fetch` | Anything that speaks the Fetch API: Hono, Elysia, Bun.serve, Deno, Cloudflare Workers, Next.js route handlers, SvelteKit, Remix |
|
|
16
|
-
| `@nxara/olio-http/node` | Node's `IncomingMessage` / `ServerResponse`: `node:http`, Express, Connect, Koa (`ctx.req`, `ctx.res`), Fastify (`request.raw`, `reply.raw`) |
|
|
17
|
-
|
|
18
|
-
Your `context` hook receives the framework's request: a Fetch `Request`, or a Node `IncomingMessage`. Once your app registers a `ctx` type (`interface Olio { ctx: … }`), the hook is required: without it graphql-http passes no context, and every resolver reading `ctx` would fail at runtime. So `fetchHandler(app)` is then a compile error (`Expected 2 arguments`), as is an options object without `context`.
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
import { fetchHandler } from "@nxara/olio-http/fetch";
|
|
22
|
-
|
|
23
|
-
const graphql = fetchHandler(app, {
|
|
24
|
-
context: (request) => createContext(request.headers.get("authorization")),
|
|
25
|
-
onOperationEnd: (ctx) => ctx.di.dispose()
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
hono.on(["GET", "POST"], "/graphql", (c) => graphql(c.req.raw)); // Hono
|
|
29
|
-
Bun.serve({ fetch: graphql }); // Bun
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
```ts
|
|
33
|
-
import { nodeHandler } from "@nxara/olio-http/node";
|
|
34
|
-
|
|
35
|
-
const graphql = nodeHandler(app, {
|
|
36
|
-
context: (req) => createContext(req.headers.authorization)
|
|
37
|
-
});
|
|
38
|
-
expressApp.all("/graphql", (req, res) => graphql(req, res)); // or: createServer(graphql)
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Subscriptions
|
|
42
|
-
|
|
43
|
-
Not included, the way Apollo Server leaves them out: install and run the reference libraries yourself, at the versions you want, next to the HTTP handler.
|
|
44
|
-
|
|
45
|
-
- [graphql-ws](https://github.com/enisdenjo/graphql-ws): subscriptions over WebSocket (`useServer` on a `ws` server, `makeHandler` on Bun).
|
|
46
|
-
- [graphql-sse](https://github.com/enisdenjo/graphql-sse): subscriptions as server-sent events, on the same URL (route `Accept: text/event-stream` to its handler).
|
|
47
|
-
|
|
48
|
-
Pass them `app.schema`; `errorMasker` hides their unexpected errors the way the HTTP handler does, and `validateOperation` applies its rules. Both, with a context (and DI scope) per subscription, disposed when it ends:
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
import type { SubscriptionContext } from "@nxara/olio";
|
|
52
|
-
import { errorMasker, validateOperation } from "@nxara/olio-http";
|
|
53
|
-
import { createHandler } from "graphql-sse/lib/use/fetch";
|
|
54
|
-
import { useServer } from "graphql-ws/use/ws";
|
|
55
|
-
|
|
56
|
-
const mask = errorMasker<SubscriptionContext>();
|
|
57
|
-
|
|
58
|
-
// graphql-sse: route requests with `Accept: text/event-stream` here, GET and
|
|
59
|
-
// POST (what @nxara/olio-client sends; single-connection mode also needs PUT and DELETE).
|
|
60
|
-
export const sseHandler = createHandler({
|
|
61
|
-
schema: app.schema,
|
|
62
|
-
context: (req) =>
|
|
63
|
-
createContext(req.raw.headers.get("authorization")) as never,
|
|
64
|
-
onSubscribe: (_req, params) => {
|
|
65
|
-
const errors = validateOperation(app.schema, params, validationRules);
|
|
66
|
-
return errors.length ? { data: null, errors: [...errors] } : undefined; // needs `data`
|
|
67
|
-
},
|
|
68
|
-
onNext: (ctx, _req, result) =>
|
|
69
|
-
mask.result(result, ctx as unknown as SubscriptionContext),
|
|
70
|
-
onComplete: (ctx) => (ctx as unknown as SubscriptionContext).di.dispose()
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// graphql-ws, on a `ws` server: `context` runs once per subscription, so the
|
|
74
|
-
// scope is per operation; keep it by connection and id to end it.
|
|
75
|
-
const live = new WeakMap<object, Map<string, SubscriptionContext>>();
|
|
76
|
-
useServer(
|
|
77
|
-
{
|
|
78
|
-
schema: app.schema,
|
|
79
|
-
context: (ctx, id) => {
|
|
80
|
-
// A browser can't set WebSocket headers: @nxara/olio-client sends them here.
|
|
81
|
-
const headers = ctx.connectionParams?.headers as
|
|
82
|
-
| Record<string, string>
|
|
83
|
-
| undefined;
|
|
84
|
-
const value = createContext(headers?.authorization);
|
|
85
|
-
live.set(ctx, (live.get(ctx) ?? new Map()).set(id, value));
|
|
86
|
-
return value as never;
|
|
87
|
-
},
|
|
88
|
-
onSubscribe: (_ctx, _id, payload) => {
|
|
89
|
-
const errors = validateOperation(app.schema, payload, validationRules);
|
|
90
|
-
return errors.length ? errors : undefined;
|
|
91
|
-
},
|
|
92
|
-
onNext: (ctx, id, _payload, _args, result) =>
|
|
93
|
-
mask.result(result, live.get(ctx)?.get(id)),
|
|
94
|
-
onError: (ctx, id, _payload, errors) =>
|
|
95
|
-
errors.map((e) => mask.error(e, live.get(ctx)?.get(id)).toJSON()),
|
|
96
|
-
// Also runs when the socket closes mid-subscription (see the note below).
|
|
97
|
-
onComplete: async (ctx, id) => {
|
|
98
|
-
const value = live.get(ctx)?.get(id);
|
|
99
|
-
live.get(ctx)?.delete(id);
|
|
100
|
-
await value?.di.dispose();
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
new WebSocketServer({ server, path: "/graphql" })
|
|
104
|
-
);
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
When a socket closes, graphql-ws ends each live subscription and waits for it before `onComplete`. A resolver that's an `async *` waiting inside `for await` can only end at its next event, so until one arrives, nothing is cleaned up. Return the event source's own iterator instead (olio's README, [Subscriptions](../olio/README.md#subscriptions)).
|
|
108
|
-
|
|
109
|
-
With `@hono/node-server`, `serve()` is typed to return HTTP/2 servers too: pass `server as Server` (from `node:http`) to `WebSocketServer`. [`apps/example-server/src/subscriptions.ts`](../../apps/example-server/src/subscriptions.ts) is all of this, running. For tests, `testClient` from `@nxara/olio-client/test` runs these same options and handler in memory, so export them (the example exports `wsOptions` and `sseHandler`).
|
|
110
|
-
|
|
111
|
-
## Refusing a bad token
|
|
112
|
-
|
|
113
|
-
Don't throw from `context`. A throw there refuses the whole request before any field runs, so a client still holding an expired token can't even call `login` to get a new one. Build a context without a user instead, and refuse in middleware; public fields skip it with `@bypass` (olio's README, [Skipping middleware](../olio/README.md#skipping-middleware-bypass)):
|
|
114
|
-
|
|
115
|
-
```ts
|
|
116
|
-
fetchHandler(app, {
|
|
117
|
-
// An invalid or expired token gives `userId: undefined`, not an error.
|
|
118
|
-
context: (request) => ({
|
|
119
|
-
userId: verify(request.headers.get("authorization"))
|
|
120
|
-
})
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const requireAuth =
|
|
124
|
-
(): MiddlewareFn =>
|
|
125
|
-
({ ctx, bypass }, next) => {
|
|
126
|
-
if (!ctx.userId && !bypass.has("auth")) throw unauthenticated();
|
|
127
|
-
return next();
|
|
128
|
-
};
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
It's also the only way that gives clients the same `UNAUTHENTICATED` result, at once, on every transport. Over subscriptions, a `context` that throws is a server error to both libraries: graphql-ws closes the socket with 4500 (the error's code is lost), graphql-sse's handler throws (your framework answers 500). Refusing the socket in graphql-ws's `onConnect` closes it with 4403, which graphql-ws's client retries by default ([@nxara/olio-client](../client/README.md#subscriptions)).
|
|
132
|
-
|
|
133
|
-
## Validation rules
|
|
134
|
-
|
|
135
|
-
`validationRules` run with graphql's own, before any resolver: a cost or depth limit, say. They're added to graphql's rules, never in their place. Pass a list, or a function of the operation (`{ variables, operationName }`) for rules that need its variables, like [graphql-query-complexity](https://github.com/slicknode/graphql-query-complexity) pricing a page by its size:
|
|
136
|
-
|
|
137
|
-
```ts
|
|
138
|
-
import {
|
|
139
|
-
createComplexityRule,
|
|
140
|
-
fieldExtensionsEstimator,
|
|
141
|
-
simpleEstimator
|
|
142
|
-
} from "graphql-query-complexity";
|
|
143
|
-
|
|
144
|
-
fetchHandler(app, {
|
|
145
|
-
context,
|
|
146
|
-
validationRules: ({ variables }) => [
|
|
147
|
-
createComplexityRule({
|
|
148
|
-
maximumComplexity: 1000,
|
|
149
|
-
variables,
|
|
150
|
-
estimators: [
|
|
151
|
-
fieldExtensionsEstimator(),
|
|
152
|
-
simpleEstimator({ defaultComplexity: 1 })
|
|
153
|
-
]
|
|
154
|
-
})
|
|
155
|
-
]
|
|
156
|
-
});
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
`fieldExtensionsEstimator` reads each field's `complexity` extension, which olio sets from the resolver's `{ resolve, extensions }`. An operation over the limit gets the rule's error, and nothing runs.
|
|
160
|
-
|
|
161
|
-
Subscription servers take the same rules through `validateOperation(schema, operation, rules)` in their `onSubscribe`; it returns the errors (none when the operation is valid):
|
|
162
|
-
|
|
163
|
-
```ts
|
|
164
|
-
import { validateOperation } from "@nxara/olio-http";
|
|
165
|
-
|
|
166
|
-
// graphql-ws
|
|
167
|
-
onSubscribe: (_ctx, _id, payload) => {
|
|
168
|
-
const errors = validateOperation(app.schema, payload, validationRules);
|
|
169
|
-
return errors.length ? errors : undefined;
|
|
170
|
-
};
|
|
171
|
-
// graphql-sse: a result needs `data` to be read as one
|
|
172
|
-
onSubscribe: (_req, params) => {
|
|
173
|
-
const errors = validateOperation(app.schema, params, validationRules);
|
|
174
|
-
return errors.length ? { data: null, errors: [...errors] } : undefined;
|
|
175
|
-
};
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## Errors
|
|
179
|
-
|
|
180
|
-
Only `GraphQLError`s reach clients. Anything else that's thrown, such as a failing database or a bug, is replaced by `"Unexpected error."` and passed to `onUnexpectedError` (default: `console.error`), so it isn't lost. That includes a `context` hook that throws: a `GraphQLError` from it (say, `BAD_REQUEST` for a malformed header) reaches the client as a normal GraphQL error with status 200; anything else is a 500 with "Unexpected error.". It refuses the whole request, so a bad token belongs in middleware instead ([Refusing a bad token](#refusing-a-bad-token)).
|
|
181
|
-
|
|
182
|
-
```ts
|
|
183
|
-
throw new GraphQLError("Forbidden", { extensions: { code: "FORBIDDEN" } }); // the client sees this
|
|
184
|
-
throw new Error("connection refused"); // the client sees "Unexpected error."
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
`onUnexpectedError(error, { ctx, request })` gets what the error happened in, so logs can tie it to a request: `ctx` is the operation's context (`undefined` when the `context` hook itself failed), `request` the adapter's (a Fetch `Request`, or Node's `IncomingMessage`).
|
|
188
|
-
|
|
189
|
-
```ts
|
|
190
|
-
fetchHandler(app, {
|
|
191
|
-
context,
|
|
192
|
-
onUnexpectedError: (error, { ctx, request }) =>
|
|
193
|
-
log.error({ error, requestId: ctx?.requestId, url: request.url })
|
|
194
|
-
});
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
`errorMasker(options?)`, from `@nxara/olio-http`, is the same masking for your own subscription servers. It takes the handlers' `maskErrors` and `onUnexpectedError` (both optional), and gives the functions below. Each takes the operation's context as a last argument, which `onUnexpectedError` receives as `ctx` (`request` is `undefined` there); type it with `errorMasker<SubscriptionContext>()`:
|
|
198
|
-
|
|
199
|
-
| | |
|
|
200
|
-
| --- | --- |
|
|
201
|
-
| `mask.result(result, ctx?)` | The result with its errors masked, any shape: graphql's `ExecutionResult`, or what graphql-sse's and graphql-ws's `onNext` hand you |
|
|
202
|
-
| `mask.error(error, ctx?)` | One error, or any caught value: a `GraphQLError` passes (unless it wraps an unexpected error), anything else becomes "Unexpected error." and is reported |
|
|
203
|
-
| `mask.report(error, ctx?)` | Sends an error to `onUnexpectedError` |
|
|
204
|
-
|
|
205
|
-
```ts
|
|
206
|
-
import { errorMasker } from "@nxara/olio-http";
|
|
207
|
-
|
|
208
|
-
const mask = errorMasker<SubscriptionContext>();
|
|
209
|
-
createHandler({
|
|
210
|
-
schema: app.schema,
|
|
211
|
-
onNext: (ctx, _req, result) => mask.result(result, ctx)
|
|
212
|
-
}); // graphql-sse
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## Options
|
|
216
|
-
|
|
217
|
-
| Option | Default | |
|
|
218
|
-
| --- | --- | --- |
|
|
219
|
-
| `context` | none | Builds `ctx` from the request. Required once the app registers a `ctx` type |
|
|
220
|
-
| `validationRules` | none | Rules run with graphql's own before execution: a list, or `({ variables, operationName }) => rules`. See [Validation rules](#validation-rules) |
|
|
221
|
-
| `onOperationEnd` | none | Called once per operation, after the response is built. Release per-operation resources here, e.g. `(ctx) => ctx.di.dispose()`. A failure in it goes to `onUnexpectedError` |
|
|
222
|
-
| `maskErrors` | `true` | Hide errors that aren't `GraphQLError`s. Turn off only while developing |
|
|
223
|
-
| `onUnexpectedError` | `console.error` of the error | `(error, { ctx, request }) => void`: receives each hidden error, with the context and request it happened in (`ctx` is `undefined` when the `context` hook failed) |
|
|
224
|
-
| graphql-http's own | its defaults | `execute`, `parse`, `validate`, `getOperationAST`, `rootValue`, `formatError` (runs after masking) and `parseRequestParams` (e.g. persisted queries: map an id to its stored query) go to [graphql-http](https://github.com/graphql/graphql-http) as they are. Not `onSubscribe`: operation args returned from it would skip `context` and every validation rule |
|
|
11
|
+
Part of [olio](https://olio.nxara.dev): modular, type-safe GraphQL for TypeScript. MIT licensed.
|
package/dist/node.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
import type
|
|
3
|
-
import {
|
|
2
|
+
import { type OperationContext } from "graphql-http";
|
|
3
|
+
import type { HandlerOptions } from "graphql-http/lib/use/http";
|
|
4
4
|
import { type GraphQLHttpOptions, type OptionsArgs, type Servable } from "./core.js";
|
|
5
5
|
type Passed = GraphQLHttpOptions<HandlerOptions<OperationContext>>;
|
|
6
|
-
export declare function nodeHandler(app: Servable, ...[options]: OptionsArgs<IncomingMessage, Passed>): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
6
|
+
export declare function nodeHandler(app: Servable, ...[options]: OptionsArgs<IncomingMessage, Passed>): (req: IncomingMessage, res: ServerResponse, body?: unknown) => Promise<void>;
|
|
7
7
|
export {};
|
|
8
8
|
//# sourceMappingURL=node.d.ts.map
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,2BAA2B,CAAC;AAEhF,OAAO,EAML,KAAK,kBAAkB,EAEvB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,WAAW,CAAC;AAEnB,KAAK,MAAM,GAAG,kBAAkB,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAiBnE,wBAAgB,WAAW,CACzB,GAAG,EAAE,QAAQ,EACb,GAAG,CAAC,OAAoD,CAAC,EAAE,WAAW,CACpE,eAAe,EACf,MAAM,CACP,GACA,CACD,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,CAAC,EAAE,OAAO,KACX,OAAO,CAAC,IAAI,CAAC,CAqDjB"}
|
package/dist/node.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import { createHandler } from "graphql-http
|
|
1
|
+
import { createHandler } from "graphql-http";
|
|
2
2
|
import { contextFailure, masking, operationEnd, handlerRules } from "./core.js";
|
|
3
|
+
const readBody = (req) => new Promise((resolve, reject) => {
|
|
4
|
+
let body = "";
|
|
5
|
+
req.setEncoding("utf8");
|
|
6
|
+
req.on("data", (chunk) => (body += chunk));
|
|
7
|
+
req.on("end", () => resolve(body));
|
|
8
|
+
req.on("error", reject);
|
|
9
|
+
});
|
|
3
10
|
export function nodeHandler(app, ...[options = {}]) {
|
|
4
11
|
const mask = masking(options);
|
|
5
12
|
const { context } = options;
|
|
@@ -23,8 +30,24 @@ export function nodeHandler(app, ...[options = {}]) {
|
|
|
23
30
|
validationRules: handlerRules(options.validationRules),
|
|
24
31
|
onOperation: (req, _args, result) => mask.result(result, { ctx: contexts.get(req.raw), request: req.raw })
|
|
25
32
|
});
|
|
26
|
-
return async (req, res) => {
|
|
27
|
-
|
|
33
|
+
return async (req, res, body) => {
|
|
34
|
+
const parsed = typeof body === "function"
|
|
35
|
+
? req.body
|
|
36
|
+
: (body ?? req.body);
|
|
37
|
+
if (parsed === undefined && req.readableEnded) {
|
|
38
|
+
mask.report(new Error("nodeHandler: the request body was already read, by a body parser? Pass the parsed body as the third argument: graphql(req, res, body)."), { ctx: undefined, request: req });
|
|
39
|
+
res.writeHead(500).end();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const [payload, init] = await http({
|
|
43
|
+
url: req.url ?? "/",
|
|
44
|
+
method: req.method ?? "GET",
|
|
45
|
+
headers: req.headers,
|
|
46
|
+
body: parsed === undefined ? () => readBody(req) : parsed,
|
|
47
|
+
raw: req,
|
|
48
|
+
context: { res }
|
|
49
|
+
});
|
|
50
|
+
res.writeHead(init.status, init.statusText, init.headers).end(payload);
|
|
28
51
|
await end(contexts.get(req), req);
|
|
29
52
|
};
|
|
30
53
|
}
|
package/dist/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxara/olio-http",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Serve an olio app over HTTP, on any framework: GraphQL over HTTP with context, error masking and per-operation cleanup.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graphql",
|
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
"check-types": "tsc -p tsconfig.test.json"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@nxara/olio-core": "0.1.
|
|
45
|
+
"@nxara/olio-core": "0.1.2",
|
|
46
46
|
"graphql-http": "^1.23.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@nxara/olio": "0.1.
|
|
49
|
+
"@nxara/olio": "0.1.2",
|
|
50
50
|
"graphql": "^16.14.2"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|