@nxgt/typespec 0.11.0 → 0.13.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 +80 -10
- package/dist/emitter.d.ts +12 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/http-operations.d.ts +9 -0
- package/dist/http-operations.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +231 -55
- package/dist/index.js.map +12 -8
- package/dist/lib.d.ts +13 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/one-reply-per-status.d.ts +1 -5
- package/dist/one-reply-per-status.d.ts.map +1 -1
- package/dist/query-method.d.ts +18 -0
- package/dist/query-method.d.ts.map +1 -0
- package/dist/query-operations.d.ts +8 -0
- package/dist/query-operations.d.ts.map +1 -0
- package/dist/verb-methods.d.ts.map +1 -1
- package/dist/verbs.d.ts +2 -2
- package/docs/README.md +1 -0
- package/docs/guide/emitter.md +159 -0
- package/docs/guide/errors.md +2 -2
- package/docs/guide/getting-started.md +9 -5
- package/docs/guide/linter.md +2 -2
- package/docs/guide/operation-ids.md +62 -5
- package/docs/roadmap.md +23 -4
- package/docs/troubleshooting.md +102 -2
- package/lib/main.tsp +1 -0
- package/lib/query-method.tsp +26 -0
- package/package.json +16 -7
- package/templates/scaffolding.json +3 -2
|
@@ -116,7 +116,7 @@ tells a cache, a proxy or a retry that the request is safe. An operation
|
|
|
116
116
|
| Verb | Sent with |
|
|
117
117
|
| --- | --- |
|
|
118
118
|
| `list`, `read`, `find`, `count`, `get` | `GET` or `HEAD` |
|
|
119
|
-
| `search`, `query` | `GET` or `POST
|
|
119
|
+
| `search`, `query` | `GET`, `POST`, or a `POST` marked [`@queryMethod`](#a-query-in-openapi-32), for criteria too large for a query string |
|
|
120
120
|
| `create`, `createMany` | `POST` |
|
|
121
121
|
| `update`, `updateMany` | `PUT` or `PATCH` |
|
|
122
122
|
| `patch` | `PATCH` |
|
|
@@ -171,10 +171,67 @@ Not checked:
|
|
|
171
171
|
whatever it says;
|
|
172
172
|
- an operation `@operationIds` does not name.
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
`
|
|
177
|
-
|
|
174
|
+
## A QUERY in OpenAPI 3.2
|
|
175
|
+
|
|
176
|
+
`QUERY` is the HTTP method for a safe request with a body, and
|
|
177
|
+
`@typespec/http` 1.17 declares only `GET`, `PUT`, `POST`, `PATCH`, `DELETE`
|
|
178
|
+
and `HEAD`. `@queryMethod` marks a `@post` as the `QUERY` it stands for:
|
|
179
|
+
|
|
180
|
+
```tsp
|
|
181
|
+
import "@typespec/http";
|
|
182
|
+
import "@nxgt/typespec";
|
|
183
|
+
|
|
184
|
+
using Http;
|
|
185
|
+
using Nxgt;
|
|
186
|
+
|
|
187
|
+
@service
|
|
188
|
+
@operationIds
|
|
189
|
+
namespace Shop;
|
|
190
|
+
|
|
191
|
+
model UserCriteria {
|
|
192
|
+
names: string[];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@route("/users")
|
|
196
|
+
interface Users {
|
|
197
|
+
@post @queryMethod @route("/search")
|
|
198
|
+
search(@body criteria: UserCriteria): string[]; // searchUsers
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
With the emitter `@nxgt/typespec` and OpenAPI 3.2 the document gets a real
|
|
203
|
+
`QUERY`, the only version that has one:
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
/users/search:
|
|
207
|
+
query:
|
|
208
|
+
operationId: searchUsers
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Anything else is an error, not a `POST` with a mark: an older version in
|
|
212
|
+
`openapi-versions` (or none, which defaults to 3.0) is `query-method-needs-openapi-3.2`, and the plain
|
|
213
|
+
`@typespec/openapi3` emitter is `query-method-needs-nxgt-emitter`
|
|
214
|
+
([troubleshooting](../troubleshooting.md)). `@nxgt/openapi-codegen`
|
|
215
|
+
generates `method: 'query'` from it
|
|
216
|
+
([TypeSpec](https://github.com/softistx/nxgt-http/blob/develop/packages/openapi-codegen/docs/guide/typespec.md)).
|
|
217
|
+
The emitter and what a real `QUERY` needs are in [The emitter](emitter.md).
|
|
218
|
+
When `@typespec/http` declares `QUERY`, the decorator is what changes, not
|
|
219
|
+
your spec ([roadmap](../roadmap.md#later)).
|
|
220
|
+
|
|
221
|
+
| Case | Result |
|
|
222
|
+
| --- | --- |
|
|
223
|
+
| `search` or `query` marked | no warning: a `QUERY` is one of their methods |
|
|
224
|
+
| `findById`, `create` or another verb marked | `verb-method-mismatch`, with the method `QUERY`: `findById is sent with QUERY, where its verb find is sent with GET or HEAD` |
|
|
225
|
+
| a name that is not a verb, marked | nothing to check |
|
|
226
|
+
| marked and not a `@post` | the error `query-method-not-post` |
|
|
227
|
+
|
|
228
|
+
```text
|
|
229
|
+
error @nxgt/typespec/query-method-not-post: list is marked @queryMethod and sent with GET: @queryMethod marks a @post, which @nxgt/typespec writes as a QUERY in OpenAPI 3.2. Make it a @post.
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
A search that answers an array also meets the linter's `list-returns-page`;
|
|
233
|
+
return a `Page<Item>`, as `search` above could
|
|
234
|
+
(`Page<User> | BadRequest`).
|
|
178
235
|
|
|
179
236
|
## The resource
|
|
180
237
|
|
package/docs/roadmap.md
CHANGED
|
@@ -16,16 +16,35 @@ Nothing in progress.
|
|
|
16
16
|
|
|
17
17
|
## Later
|
|
18
18
|
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
- **A `QUERY` without a mark.** A real `QUERY` is done: the emitter
|
|
20
|
+
`@nxgt/typespec` writes a `@queryMethod` as a `query` operation in OpenAPI
|
|
21
|
+
3.2. What is left is a native `@query`-like verb, once `@typespec/http`
|
|
22
|
+
declares `QUERY`, so a spec stops needing `@post @queryMethod` and does not
|
|
23
|
+
otherwise change.
|
|
23
24
|
- **`ETag` and conditional requests.** `ETag`, with `If-None-Match` and
|
|
24
25
|
`If-Match`, once the `@nxgt/*` packages send one the same way. The
|
|
25
26
|
optimistic lock is the body's `version` today (`Versioned`).
|
|
26
27
|
|
|
27
28
|
## Shipped
|
|
28
29
|
|
|
30
|
+
### 0.13.0
|
|
31
|
+
|
|
32
|
+
- **The emitter `@nxgt/typespec`.** `emit: ["@nxgt/typespec"]` runs
|
|
33
|
+
`@typespec/openapi3` with the same options and files, and in an OpenAPI 3.2
|
|
34
|
+
document writes each `@queryMethod` as a real `query` operation, which
|
|
35
|
+
`@nxgt/openapi-codegen` generates as `method: 'query'` and
|
|
36
|
+
`@nxgt/openapi-hono` serves. A marked operation with an older version, or
|
|
37
|
+
with plain `@typespec/openapi3`, is an error. `@typespec/openapi3` is an optional peer, and the
|
|
38
|
+
`tsp init` template emits with the new emitter.
|
|
39
|
+
|
|
40
|
+
### 0.12.0
|
|
41
|
+
|
|
42
|
+
- **`@queryMethod`, a `QUERY` sent as a `POST`.** The decorator marks a
|
|
43
|
+
`@post` with `x-nxgt-method: query`, which `@nxgt/openapi-codegen` reads,
|
|
44
|
+
and `search` and `query` accept it: a safe request with a body, with every
|
|
45
|
+
server, proxy and `fetch`. On anything but a `@post` it is the error
|
|
46
|
+
`query-method-not-post`.
|
|
47
|
+
|
|
29
48
|
### 0.11.0
|
|
30
49
|
|
|
31
50
|
- **Request body aliases.** `CreateRequest<T>`, `UpdateRequest<T>` and
|
package/docs/troubleshooting.md
CHANGED
|
@@ -293,6 +293,104 @@ Or silence that one operation with a reason:
|
|
|
293
293
|
@post @route("/find") findById(@body id: uuid): User;
|
|
294
294
|
```
|
|
295
295
|
|
|
296
|
+
## `list is marked @queryMethod and sent with GET: @queryMethod marks a @post, which @nxgt/typespec writes as a QUERY in OpenAPI 3.2. Make it a @post.`
|
|
297
|
+
|
|
298
|
+
**When:** an error, `query-method-not-post`: an operation marked
|
|
299
|
+
`@queryMethod` is sent with a method other than `POST`. The method may be
|
|
300
|
+
implicit, `@get` or none.
|
|
301
|
+
|
|
302
|
+
```tsp
|
|
303
|
+
@route("/users")
|
|
304
|
+
interface Users {
|
|
305
|
+
@get @queryMethod list(): string[];
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Why:** `@queryMethod` stands for a `QUERY` that `@typespec/http` cannot
|
|
310
|
+
declare, so the spec writes a `@post` and the emitter writes the `QUERY`
|
|
311
|
+
([The emitter](guide/emitter.md)); on a `GET`, a `PUT` or a `DELETE` it has
|
|
312
|
+
nothing to stand for.
|
|
313
|
+
|
|
314
|
+
**Fix:** make it a `@post`, with the criteria in the body:
|
|
315
|
+
|
|
316
|
+
```tsp
|
|
317
|
+
@post @queryMethod @route("/search") search(@body names: string[]): string[];
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Or drop `@queryMethod`: a `GET` needs no mark. More, in
|
|
321
|
+
[Operation ids](guide/operation-ids.md#a-query-in-openapi-32).
|
|
322
|
+
|
|
323
|
+
## `search is marked @queryMethod: only OpenAPI 3.2 has a QUERY operation, and openapi-versions asks for 3.1.0. Emit 3.2 only, or take off @queryMethod.`
|
|
324
|
+
|
|
325
|
+
**When:** `tsp compile` with the emitter `@nxgt/typespec`; the error
|
|
326
|
+
`query-method-needs-openapi-3.2` on each marked operation. Nothing is emitted.
|
|
327
|
+
|
|
328
|
+
**Why:** OpenAPI 3.1 and older have no `QUERY` operation, and the emitter
|
|
329
|
+
does not turn the operation into a `POST`. `openapi-versions` holds a version
|
|
330
|
+
below 3.2, or is unset, which means 3.0.0; the message names the first such
|
|
331
|
+
version.
|
|
332
|
+
|
|
333
|
+
**Fix:** emit 3.2 only, or take off `@queryMethod` and use a plain `@post`
|
|
334
|
+
or `@get`:
|
|
335
|
+
|
|
336
|
+
```yaml
|
|
337
|
+
options:
|
|
338
|
+
'@nxgt/typespec':
|
|
339
|
+
openapi-versions: ['3.2.0']
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
An `openapi-versions` with 3.2 beside an older version fails the same way:
|
|
343
|
+
list only 3.2. More, in [The emitter](guide/emitter.md).
|
|
344
|
+
|
|
345
|
+
## `search is marked @queryMethod: emit with @nxgt/typespec, which writes it as a QUERY; @typespec/openapi3 would write a POST.`
|
|
346
|
+
|
|
347
|
+
**When:** `tsp compile` with `@typespec/openapi3` in `emit`; the error
|
|
348
|
+
`query-method-needs-nxgt-emitter` on each marked operation. Since 0.13.0; in
|
|
349
|
+
0.12.0 this compiled to a `post` with `x-nxgt-method: query`.
|
|
350
|
+
|
|
351
|
+
**Why:** only the emitter `@nxgt/typespec` writes a `@queryMethod` as a
|
|
352
|
+
`QUERY`.
|
|
353
|
+
|
|
354
|
+
**Fix:** emit with it, and ask for 3.2:
|
|
355
|
+
|
|
356
|
+
```yaml
|
|
357
|
+
emit:
|
|
358
|
+
- '@nxgt/typespec'
|
|
359
|
+
options:
|
|
360
|
+
'@nxgt/typespec':
|
|
361
|
+
openapi-versions: ['3.2.0']
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## `The emitter @nxgt/typespec runs @typespec/openapi3, which is not installed: add it beside @nxgt/typespec.`
|
|
365
|
+
|
|
366
|
+
**When:** `tsp compile` with `@nxgt/typespec` in `emit`; the error
|
|
367
|
+
`openapi3-missing`. Nothing is emitted.
|
|
368
|
+
|
|
369
|
+
**Why:** `@typespec/openapi3` is an optional peer of `@nxgt/typespec`, loaded
|
|
370
|
+
only when the spec is emitted, so installing the library does not install it.
|
|
371
|
+
|
|
372
|
+
**Fix:**
|
|
373
|
+
|
|
374
|
+
```sh
|
|
375
|
+
bun add -d @typespec/openapi3
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## `findById is sent with QUERY, where its verb find is sent with GET or HEAD`
|
|
379
|
+
|
|
380
|
+
**When:** a warning, `verb-method-mismatch`: an operation named after one of
|
|
381
|
+
the library's verbs other than `search` and `query` is marked `@queryMethod`.
|
|
382
|
+
|
|
383
|
+
**Why:** a marked `POST` is checked as the `QUERY` it is, and only `search`
|
|
384
|
+
and `query` are sent with `QUERY`.
|
|
385
|
+
|
|
386
|
+
**Fix:** name it `search` or `query`, a name that is not a verb, or take off
|
|
387
|
+
`@queryMethod` and give the verb its own method, as in the entry on
|
|
388
|
+
[`findById is sent with POST`](#findbyid-is-sent-with-post-where-its-verb-find-is-sent-with-get-or-head).
|
|
389
|
+
|
|
390
|
+
```tsp
|
|
391
|
+
@post @queryMethod @route("/search") searchByName(@body names: string[]): User[]; // searchUserByName
|
|
392
|
+
```
|
|
393
|
+
|
|
296
394
|
## `declares a reply without a body and one with a body of status …`
|
|
297
395
|
|
|
298
396
|
**When:** an operation declares, for one status, a reply without a body and
|
|
@@ -600,7 +698,9 @@ using OpenAPI;
|
|
|
600
698
|
|
|
601
699
|
**When:** you generate from what `tsp compile` emitted.
|
|
602
700
|
|
|
603
|
-
**Why:** `@typespec/openapi3`
|
|
701
|
+
**Why:** `@typespec/openapi3`, and so `@nxgt/typespec` which runs it, emits
|
|
702
|
+
OpenAPI 3.0 by default.
|
|
604
703
|
|
|
605
704
|
**Fix:** in `tspconfig.yaml`, set `openapi-versions: ['3.1.0']` or
|
|
606
|
-
`['3.2.0']` under the `@typespec
|
|
705
|
+
`['3.2.0']` under the options of the emitter you use, `@nxgt/typespec`
|
|
706
|
+
or `@typespec/openapi3`.
|
package/lib/main.tsp
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import "@typespec/openapi";
|
|
2
|
+
|
|
3
|
+
using TypeSpec.Reflection;
|
|
4
|
+
|
|
5
|
+
namespace Nxgt;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Marks a `POST` as a `QUERY`: a safe request, which changes nothing on the
|
|
9
|
+
* server, with its criteria in the body. It is sent as a `POST`, which every
|
|
10
|
+
* server, proxy and `fetch` accepts, and the OpenAPI document says what it is
|
|
11
|
+
* with `x-nxgt-method: query`: `@nxgt/openapi-codegen` reads it. Once
|
|
12
|
+
* `@typespec/http` declares `QUERY`, this is the decorator that changes, not
|
|
13
|
+
* the spec. Only on a `POST`: anything else is the error
|
|
14
|
+
* `query-method-not-post`. `@operationIds` checks its verb as a `QUERY`'s:
|
|
15
|
+
* `search` and `query` take one.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typespec
|
|
19
|
+
* @route("/users")
|
|
20
|
+
* interface Users {
|
|
21
|
+
* @post @queryMethod @route("/search")
|
|
22
|
+
* search(@body criteria: UserCriteria): User[]; // searchUsers
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
extern dec queryMethod(target: Operation);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxgt/typespec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,20 +45,29 @@
|
|
|
45
45
|
"src/index.ts"
|
|
46
46
|
]
|
|
47
47
|
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"yaml": "^2.9.0"
|
|
50
|
+
},
|
|
48
51
|
"peerDependencies": {
|
|
49
52
|
"@typespec/compiler": "^1.16.0",
|
|
50
53
|
"@typespec/http": "^1.16.0",
|
|
51
54
|
"@typespec/openapi": "^1.16.0",
|
|
52
|
-
"typescript": "^6.0.3 || ^7.0.0"
|
|
55
|
+
"typescript": "^6.0.3 || ^7.0.0",
|
|
56
|
+
"@typespec/openapi3": "^1.16.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependenciesMeta": {
|
|
59
|
+
"@typespec/openapi3": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
53
62
|
},
|
|
54
63
|
"devDependencies": {
|
|
55
|
-
"@nxgt/openapi-codegen": "^0.
|
|
64
|
+
"@nxgt/openapi-codegen": "^0.9.1",
|
|
56
65
|
"@nxgt/openapi-hono": "^0.3.2",
|
|
57
66
|
"@types/bun": "^1.4.0",
|
|
58
|
-
"@typespec/compiler": "1.
|
|
59
|
-
"@typespec/http": "1.
|
|
60
|
-
"@typespec/openapi": "1.
|
|
61
|
-
"@typespec/openapi3": "1.
|
|
67
|
+
"@typespec/compiler": "1.17.0",
|
|
68
|
+
"@typespec/http": "1.17.0",
|
|
69
|
+
"@typespec/openapi": "1.17.0",
|
|
70
|
+
"@typespec/openapi3": "1.17.0",
|
|
62
71
|
"hono": "^4.13.4",
|
|
63
72
|
"zod": "^4.5.4"
|
|
64
73
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"libraries": [
|
|
7
7
|
"@typespec/http",
|
|
8
8
|
"@typespec/openapi",
|
|
9
|
+
"@typespec/openapi3",
|
|
9
10
|
"@nxgt/typespec",
|
|
10
11
|
"@nxgt/openapi-codegen"
|
|
11
12
|
],
|
|
@@ -15,9 +16,9 @@
|
|
|
15
16
|
}
|
|
16
17
|
},
|
|
17
18
|
"emitters": {
|
|
18
|
-
"@typespec
|
|
19
|
+
"@nxgt/typespec": {
|
|
19
20
|
"selected": true,
|
|
20
|
-
"label": "OpenAPI 3.1 document",
|
|
21
|
+
"label": "OpenAPI 3.1 document (@typespec/openapi3; in 3.2, a @queryMethod is a QUERY)",
|
|
21
22
|
"options": {
|
|
22
23
|
"emitter-output-dir": "{project-root}/openapi",
|
|
23
24
|
"openapi-versions": ["3.1.0"],
|