nitro-openapi-schemas 2.0.0 → 3.0.0
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 +33 -51
- package/dist/index.d.mts +4 -7
- package/dist/index.mjs +2 -2
- package/dist/runtime/route.mjs +3 -3
- package/package.json +3 -8
- package/dist/h3.d.mts +0 -36
- package/dist/h3.mjs +0 -27
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# nitro-openapi-schemas
|
|
2
2
|
|
|
3
|
-
[](https://github.com/oumarbarry/nitro-openapi-schemas/actions/workflows/ci.yml)
|
|
4
|
+
[](https://npmjs.com/package/nitro-openapi-schemas)
|
|
5
5
|
[](https://github.com/oumarbarry/nitro-openapi-schemas/blob/main/LICENSE)
|
|
6
6
|
|
|
7
7
|
Schema-driven OpenAPI for [Nitro](https://nitro.build). The Zod, Valibot or
|
|
@@ -17,9 +17,8 @@ Zod / Valibot / ArkType schema
|
|
|
17
17
|
→ openapi.json written after `nitro build`, ready for SDK codegen
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
want the [`main` branch](https://github.com/oumarbarry/nitro-openapi-schemas/tree/main) and the `latest` tag.
|
|
20
|
+
- Nitro v3 and h3 v2, published as 3.x under the `latest` tag. Nitro v2 and
|
|
21
|
+
Nuxt 4 have their own line, see [below](#nitro-v2-and-nuxt-4).
|
|
23
22
|
- Zod 4.2+, ArkType 2.1.28+, and Valibot through `@valibot/to-json-schema`
|
|
24
23
|
1.5+, via [Standard JSON Schema](https://github.com/standard-schema/standard-schema/pull/134).
|
|
25
24
|
Bring the one you use; none is installed for you.
|
|
@@ -29,7 +28,7 @@ Zod / Valibot / ArkType schema
|
|
|
29
28
|
## Install
|
|
30
29
|
|
|
31
30
|
```sh
|
|
32
|
-
bun add nitro-openapi-schemas
|
|
31
|
+
bun add nitro-openapi-schemas # or npm, pnpm
|
|
33
32
|
```
|
|
34
33
|
|
|
35
34
|
## Usage
|
|
@@ -38,10 +37,10 @@ Register the module and, optionally, the `info` block of the spec:
|
|
|
38
37
|
|
|
39
38
|
```ts
|
|
40
39
|
// nitro.config.ts
|
|
41
|
-
import {
|
|
40
|
+
import { defineConfig } from "nitro";
|
|
42
41
|
import openAPISchemas from "nitro-openapi-schemas";
|
|
43
42
|
|
|
44
|
-
export default
|
|
43
|
+
export default defineConfig({
|
|
45
44
|
modules: [openAPISchemas],
|
|
46
45
|
openAPISchemas: {
|
|
47
46
|
info: { title: "Payments API", version: "1.0.0" },
|
|
@@ -51,28 +50,14 @@ export default defineNitroConfig({
|
|
|
51
50
|
});
|
|
52
51
|
```
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
export default defineNuxtConfig({
|
|
59
|
-
nitro: {
|
|
60
|
-
modules: [openAPISchemas],
|
|
61
|
-
openAPISchemas: { info: { title: "Payments API", version: "1.0.0" } },
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Then write routes with `defineValidatedHandler` from `nitro-openapi-schemas/h3`.
|
|
67
|
-
It validates `query`, `headers` and `body` through each schema's own
|
|
68
|
-
`~standard.validate` (400 with the issues in `data` on failure, body skipped
|
|
69
|
-
for GET and HEAD) and documents them. `meta.openAPI` is merged into the
|
|
70
|
-
operation, and a `schema` on a response is converted too:
|
|
53
|
+
Then write routes with `defineValidatedHandler` from `nitro/h3`. The `body`,
|
|
54
|
+
`query` and `headers` schemas are validated by h3 and documented by this
|
|
55
|
+
module. `meta.openAPI` is merged into the operation, and a `schema` on a
|
|
56
|
+
response is converted too:
|
|
71
57
|
|
|
72
58
|
```ts
|
|
73
|
-
// routes/api/payments/index.post.ts
|
|
74
|
-
import {
|
|
75
|
-
import { defineValidatedHandler } from "nitro-openapi-schemas/h3";
|
|
59
|
+
// routes/api/payments/index.post.ts
|
|
60
|
+
import { defineValidatedHandler } from "nitro/h3";
|
|
76
61
|
import { createPaymentSchema, paymentSchema } from "../../shared/schema.ts";
|
|
77
62
|
|
|
78
63
|
export default defineValidatedHandler({
|
|
@@ -85,17 +70,15 @@ export default defineValidatedHandler({
|
|
|
85
70
|
},
|
|
86
71
|
},
|
|
87
72
|
handler: async (event) => {
|
|
88
|
-
const body = await
|
|
73
|
+
const body = await event.req.json(); // already validated
|
|
89
74
|
// ...
|
|
90
75
|
},
|
|
91
76
|
});
|
|
92
77
|
```
|
|
93
78
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
documented from the route pattern, so `defineValidatedHandler` with only `meta`
|
|
98
|
-
is enough for a route without validation.
|
|
79
|
+
Start the server and open `/_scalar`, or fetch `/_openapi.json`. Path
|
|
80
|
+
parameters are documented from the route pattern, so a plain `defineHandler`
|
|
81
|
+
with `meta` is enough for a route without validation.
|
|
99
82
|
|
|
100
83
|
### Naming components
|
|
101
84
|
|
|
@@ -125,25 +108,25 @@ bun run openapi # nitro build, boot the output, write openapi.json
|
|
|
125
108
|
bun run sdk # openapi-typescript openapi.json -o sdk.d.ts
|
|
126
109
|
```
|
|
127
110
|
|
|
128
|
-
## Nitro
|
|
111
|
+
## Nitro v2 and Nuxt 4
|
|
129
112
|
|
|
130
|
-
The `
|
|
131
|
-
|
|
132
|
-
|
|
113
|
+
The `v2` dist-tag targets `nitropack` 2.x and h3 1.x, which is what Nuxt 4
|
|
114
|
+
ships. h3 1.x has no `defineValidatedHandler`, so that line provides one at
|
|
115
|
+
`nitro-openapi-schemas/h3`. Install with `bun add nitro-openapi-schemas@v2`
|
|
116
|
+
and read the [`nitro-v2` branch](https://github.com/oumarbarry/nitro-openapi-schemas/tree/nitro-v2) README.
|
|
133
117
|
|
|
134
118
|
## How it works
|
|
135
119
|
|
|
136
120
|
The module emits a virtual module that imports every scanned route handler
|
|
137
|
-
directly, bypassing Nitro's lazy wrappers
|
|
138
|
-
`
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
121
|
+
directly, bypassing Nitro's lazy wrappers, because h3's `defineValidatedHandler`
|
|
122
|
+
and `defineHandler` assign the definition, `validate` schemas and `meta`
|
|
123
|
+
included, onto the handler function. The spec route reads those live objects,
|
|
124
|
+
converts each schema through `~standard.jsonSchema` (or wraps it with
|
|
125
|
+
`@valibot/to-json-schema` when the library does not expose that yet), hoists
|
|
126
|
+
named schemas and Zod's nested `$defs` into `components/schemas`, and caches
|
|
127
|
+
the document after the first request.
|
|
144
128
|
|
|
145
129
|
The trade-off: routes imported by the spec route are no longer lazy-loaded.
|
|
146
|
-
Nuxt's catch-all renderer (`/**`) is left out of the import for that reason.
|
|
147
130
|
|
|
148
131
|
## Limitations
|
|
149
132
|
|
|
@@ -170,11 +153,10 @@ works as a standalone module.
|
|
|
170
153
|
|
|
171
154
|
```sh
|
|
172
155
|
bun install && bun install --force # the second install links the built dist/ into the examples
|
|
173
|
-
bun run dev
|
|
174
|
-
bun run check
|
|
175
|
-
bun run build
|
|
176
|
-
bun run openapi
|
|
177
|
-
bun run openapi:nuxt4 # same for examples/nuxt4
|
|
156
|
+
bun run dev # example app at http://localhost:3000/_scalar
|
|
157
|
+
bun run check # oxlint + oxfmt
|
|
158
|
+
bun run build # obuild, writes dist/
|
|
159
|
+
bun run openapi # end-to-end: build the example and write its openapi.json
|
|
178
160
|
```
|
|
179
161
|
|
|
180
162
|
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NitroModule } from "
|
|
1
|
+
import { NitroModule } from "nitro/types";
|
|
2
2
|
interface NitroOpenAPISchemasOptions {
|
|
3
3
|
/** Route serving the generated spec. Default: `/_openapi.json` */
|
|
4
4
|
route?: string;
|
|
@@ -11,7 +11,7 @@ interface NitroOpenAPISchemasOptions {
|
|
|
11
11
|
description?: string;
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
|
-
declare module "
|
|
14
|
+
declare module "nitro/types" {
|
|
15
15
|
interface NitroConfig {
|
|
16
16
|
openAPISchemas?: NitroOpenAPISchemasOptions;
|
|
17
17
|
}
|
|
@@ -20,13 +20,10 @@ declare module "nitropack/types" {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Nitro v2 / Nuxt 4 line.
|
|
24
|
-
*
|
|
25
23
|
* Emits a virtual module that imports every scanned route handler *directly*
|
|
26
24
|
* (bypassing lazy wrappers), so the spec route can read the live `validate`
|
|
27
|
-
* schemas and `meta`
|
|
28
|
-
*
|
|
29
|
-
* that attaches them.
|
|
25
|
+
* schemas and `meta` that h3's defineValidatedHandler/defineHandler attach to
|
|
26
|
+
* the handler function at runtime.
|
|
30
27
|
*/
|
|
31
28
|
declare const nitroOpenAPISchemas: NitroModule;
|
|
32
29
|
export { NitroOpenAPISchemasOptions, nitroOpenAPISchemas as default };
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { runtimeDir } from "
|
|
3
|
+
import { runtimeDir } from "nitro/meta";
|
|
4
4
|
const nitroOpenAPISchemas = {
|
|
5
5
|
name: "nitro-openapi-schemas",
|
|
6
6
|
setup(nitro) {
|
|
7
7
|
const options = nitro.options.openAPISchemas || {};
|
|
8
8
|
const specRoute = options.route || "/_openapi.json";
|
|
9
9
|
nitro.options.virtual["#nitro-openapi-schemas"] = () => {
|
|
10
|
-
const entries =
|
|
10
|
+
const entries = Object.values(nitro.routing.routes.routes).flatMap((r) => r.data).filter((h) => h.route && h.route !== specRoute && !h.route.startsWith("/_") && typeof h.handler === "string");
|
|
11
11
|
const files = [...new Set(entries.map((h) => h.handler))];
|
|
12
12
|
return [
|
|
13
13
|
...files.map((file, i) => `import h${i} from ${JSON.stringify(file)};`),
|
package/dist/runtime/route.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineHandler } from "h3";
|
|
2
2
|
// @ts-expect-error virtual module provided by ../index.ts
|
|
3
3
|
import { routes, config } from "#nitro-openapi-schemas";
|
|
4
4
|
import { toOpenAPIDocument } from "./generator.mjs";
|
|
5
5
|
let cached;
|
|
6
|
-
export default
|
|
6
|
+
export default defineHandler((event) => {
|
|
7
7
|
|
|
8
|
-
const origin =
|
|
8
|
+
const origin = new URL(event.req.url).origin;
|
|
9
9
|
return cached ??= toOpenAPIDocument(routes, {
|
|
10
10
|
info: config.info,
|
|
11
11
|
servers: [{ url: origin }]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitro-openapi-schemas",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Schema-driven OpenAPI for Nitro: the Zod, Valibot or ArkType schema that validates a route also documents it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -35,10 +35,6 @@
|
|
|
35
35
|
".": {
|
|
36
36
|
"types": "./dist/index.d.mts",
|
|
37
37
|
"default": "./dist/index.mjs"
|
|
38
|
-
},
|
|
39
|
-
"./h3": {
|
|
40
|
-
"types": "./dist/h3.d.mts",
|
|
41
|
-
"default": "./dist/h3.mjs"
|
|
42
38
|
}
|
|
43
39
|
},
|
|
44
40
|
"publishConfig": {
|
|
@@ -47,7 +43,6 @@
|
|
|
47
43
|
"scripts": {
|
|
48
44
|
"dev": "bun run --cwd examples/nitro dev",
|
|
49
45
|
"openapi": "bun run --cwd examples/nitro openapi",
|
|
50
|
-
"openapi:nuxt4": "bun run --cwd examples/nuxt4 openapi",
|
|
51
46
|
"sdk": "bun run --cwd examples/nitro sdk",
|
|
52
47
|
"build": "obuild",
|
|
53
48
|
"prepare": "obuild",
|
|
@@ -69,8 +64,8 @@
|
|
|
69
64
|
"peerDependencies": {
|
|
70
65
|
"@valibot/to-json-schema": "^1.5.0",
|
|
71
66
|
"arktype": "^2.1.28",
|
|
72
|
-
"h3": "^1.
|
|
73
|
-
"
|
|
67
|
+
"h3": "^2.0.1-rc.22",
|
|
68
|
+
"nitro": "^3.0.260610-beta",
|
|
74
69
|
"zod": "^4.2.0"
|
|
75
70
|
},
|
|
76
71
|
"peerDependenciesMeta": {
|
package/dist/h3.d.mts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { EventHandler, EventHandlerObject, EventHandlerRequest, EventHandlerResponse } from "h3";
|
|
2
|
-
interface StandardSchema {
|
|
3
|
-
"~standard": {
|
|
4
|
-
vendor: string;
|
|
5
|
-
version: number;
|
|
6
|
-
validate: (value: unknown) => {
|
|
7
|
-
value: unknown;
|
|
8
|
-
issues?: undefined;
|
|
9
|
-
} | {
|
|
10
|
-
issues: readonly unknown[];
|
|
11
|
-
} | Promise<{
|
|
12
|
-
value: unknown;
|
|
13
|
-
issues?: undefined;
|
|
14
|
-
} | {
|
|
15
|
-
issues: readonly unknown[];
|
|
16
|
-
}>;
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
interface ValidateSchemas {
|
|
20
|
-
body?: StandardSchema;
|
|
21
|
-
query?: StandardSchema;
|
|
22
|
-
headers?: StandardSchema;
|
|
23
|
-
}
|
|
24
|
-
interface HandlerMeta {
|
|
25
|
-
openAPI?: Record<string, any>;
|
|
26
|
-
[key: string]: unknown;
|
|
27
|
-
}
|
|
28
|
-
type ValidatedHandler<Request extends EventHandlerRequest = EventHandlerRequest, Response = EventHandlerResponse> = EventHandler<Request, Response> & {
|
|
29
|
-
validate?: ValidateSchemas;
|
|
30
|
-
meta?: HandlerMeta;
|
|
31
|
-
};
|
|
32
|
-
declare function defineValidatedHandler<Request extends EventHandlerRequest = EventHandlerRequest, Response = EventHandlerResponse>(def: EventHandlerObject<Request, Response> & {
|
|
33
|
-
validate?: ValidateSchemas;
|
|
34
|
-
meta?: HandlerMeta;
|
|
35
|
-
}): ValidatedHandler<Request, Response>;
|
|
36
|
-
export { HandlerMeta, ValidateSchemas, ValidatedHandler, defineValidatedHandler };
|
package/dist/h3.mjs
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { createError, defineEventHandler, getQuery, getRequestHeaders, readBody } from "h3";
|
|
2
|
-
function defineValidatedHandler(def) {
|
|
3
|
-
const { validate, meta } = def;
|
|
4
|
-
const handler = defineEventHandler({
|
|
5
|
-
...def,
|
|
6
|
-
handler: async (event) => {
|
|
7
|
-
if (validate?.query) await validatePart(validate.query, getQuery(event), "query");
|
|
8
|
-
if (validate?.headers) await validatePart(validate.headers, getRequestHeaders(event), "headers");
|
|
9
|
-
if (validate?.body && event.method !== "GET" && event.method !== "HEAD") await validatePart(validate.body, await readBody(event), "body");
|
|
10
|
-
return def.handler(event);
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
return Object.assign(handler, {
|
|
14
|
-
validate,
|
|
15
|
-
meta
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
async function validatePart(schema, value, part) {
|
|
19
|
-
const result = await schema["~standard"].validate(value);
|
|
20
|
-
if (result.issues) throw createError({
|
|
21
|
-
status: 400,
|
|
22
|
-
statusMessage: "Validation Error",
|
|
23
|
-
message: `Invalid ${part}`,
|
|
24
|
-
data: result.issues
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
export { defineValidatedHandler };
|