@nxgt/typespec 0.2.0 → 0.4.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 +41 -47
- package/dist/index.js +48 -8
- package/dist/index.js.map +4 -4
- package/dist/lib.d.ts.map +1 -1
- package/dist/operation-ids.d.ts +15 -11
- package/dist/operation-ids.d.ts.map +1 -1
- package/docs/README.md +2 -2
- package/docs/guide/auth.md +3 -3
- package/docs/guide/columns.md +1 -1
- package/docs/guide/errors.md +3 -3
- package/docs/guide/headers.md +2 -2
- package/docs/guide/operation-ids.md +152 -63
- package/docs/guide/pagination.md +3 -3
- package/docs/guide/sorting.md +131 -0
- package/docs/roadmap.md +20 -5
- package/docs/troubleshooting.md +44 -24
- package/lib/main.tsp +1 -1
- package/lib/operation-ids.tsp +13 -8
- package/lib/sorting.tsp +20 -0
- package/package.json +2 -2
- package/docs/guide/resources.md +0 -112
- package/lib/resources.tsp +0 -63
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxgt/typespec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"typescript": "^6.0.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@nxgt/openapi-codegen": "^0.5.
|
|
54
|
+
"@nxgt/openapi-codegen": "^0.5.1",
|
|
55
55
|
"@nxgt/openapi-hono": "^0.3.0",
|
|
56
56
|
"@types/bun": "^1.4.0",
|
|
57
57
|
"@typespec/compiler": "1.16.0",
|
package/docs/guide/resources.md
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# Resources
|
|
2
|
-
|
|
3
|
-
`Resource` gives a resource its five operations in one line: list, read,
|
|
4
|
-
create, update and delete, with the replies each one can send.
|
|
5
|
-
|
|
6
|
-
## One resource
|
|
7
|
-
|
|
8
|
-
```tsp
|
|
9
|
-
import "@typespec/http";
|
|
10
|
-
import "@nxgt/typespec";
|
|
11
|
-
|
|
12
|
-
using Http;
|
|
13
|
-
using Nxgt;
|
|
14
|
-
|
|
15
|
-
namespace Blog;
|
|
16
|
-
|
|
17
|
-
model Author {
|
|
18
|
-
@visibility(Lifecycle.Read) id: uuid;
|
|
19
|
-
name: string;
|
|
20
|
-
email: email;
|
|
21
|
-
...Timestamps;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
model AuthorFilters {
|
|
25
|
-
/** Authors of this name. */
|
|
26
|
-
@query name?: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
@route("/authors")
|
|
30
|
-
interface Authors extends Resource<Author, AuthorFilters, SortField = "name" | "createdAt"> {}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
| Operation | Route | Body | Answers |
|
|
34
|
-
| --- | --- | --- | --- |
|
|
35
|
-
| `listAuthors` | `GET /authors` | | `Page<Author>` |
|
|
36
|
-
| `readAuthors` | `GET /authors/{id}` | | `Author`, `NotFound` |
|
|
37
|
-
| `createAuthors` | `POST /authors` | `Create<Author>` | 201 `Author`, `BadRequest`, `Conflict` |
|
|
38
|
-
| `updateAuthors` | `PATCH /authors/{id}` | `MergePatchUpdate<Author>` | `Author`, `BadRequest`, `NotFound`, `Conflict` |
|
|
39
|
-
| `deleteAuthors` | `DELETE /authors/{id}` | | 204, `NotFound` |
|
|
40
|
-
|
|
41
|
-
The template carries `@operationIds`, so each operation is named after the
|
|
42
|
-
interface that extends it. The generator's own 400 is on every operation
|
|
43
|
-
that takes a parameter or a body, as always.
|
|
44
|
-
|
|
45
|
-
## The template's arguments
|
|
46
|
-
|
|
47
|
-
`Resource<Item, Filters = {}, SortField = "id", Id = uuid>`. Name the ones
|
|
48
|
-
after `Filters`, as above, to skip those you keep:
|
|
49
|
-
|
|
50
|
-
- `Item`: the resource's model. `Create<Item>` and `MergePatchUpdate<Item>`
|
|
51
|
-
leave its read-only properties out, such as `id` and the `Timestamps`.
|
|
52
|
-
- `Filters`: a model of `@query` properties, spread into `list`. Each is
|
|
53
|
-
typed and checked, as any query parameter.
|
|
54
|
-
- `SortField`: the fields `list` may sort by, as a union of strings.
|
|
55
|
-
- `Id`: the type of `{id}`. `Id = integer` for a table whose id is
|
|
56
|
-
`@nxgt/drizzle`'s `id('identity')`.
|
|
57
|
-
|
|
58
|
-
## Filters and sort
|
|
59
|
-
|
|
60
|
-
`list` takes the filters, the offset page's `page` and `pageSize`, and
|
|
61
|
-
`SortParameters<SortField>`:
|
|
62
|
-
|
|
63
|
-
| Query | Default | Checked |
|
|
64
|
-
| --- | --- | --- |
|
|
65
|
-
| `orderBy` | none: the server's order, the primary key with `@nxgt/drizzle` | one of the `SortField`s |
|
|
66
|
-
| `direction` | `asc` | `asc` or `desc` |
|
|
67
|
-
|
|
68
|
-
`?orderBy=email` on `Authors` is a 400: `email` is not a `SortField`. The
|
|
69
|
-
handler passes them to `@nxgt/drizzle`:
|
|
70
|
-
|
|
71
|
-
```ts
|
|
72
|
-
import { Hono } from 'hono';
|
|
73
|
-
import { createRoutes } from './generated/hono';
|
|
74
|
-
|
|
75
|
-
const app = new Hono();
|
|
76
|
-
createRoutes(app).get('/authors', async (c) => {
|
|
77
|
-
const { name, page, pageSize, orderBy, direction } = c.req.valid('query');
|
|
78
|
-
const found = await authors.paginate({
|
|
79
|
-
where: name === undefined ? {} : { name },
|
|
80
|
-
page,
|
|
81
|
-
pageSize,
|
|
82
|
-
// paginate takes the sort as an object of directions by field
|
|
83
|
-
...(orderBy === undefined ? {} : { orderBy: { [orderBy]: direction } }),
|
|
84
|
-
});
|
|
85
|
-
return c.json(found, 200);
|
|
86
|
-
});
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
`paginateByCursor` takes them apart instead, `{ orderBy, direction }`, as
|
|
90
|
-
the query has them.
|
|
91
|
-
|
|
92
|
-
`SortParameters<Field>` works on its own too, in any list:
|
|
93
|
-
|
|
94
|
-
```tsp
|
|
95
|
-
@get list(...PageParameters, ...SortParameters<"createdAt" | "title">): Page<Post>;
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Changing an operation
|
|
99
|
-
|
|
100
|
-
An interface that extends `Resource` can declare one of its operations
|
|
101
|
-
again, and its own replaces the template's. A list paged by cursor:
|
|
102
|
-
|
|
103
|
-
```tsp
|
|
104
|
-
@route("/comments")
|
|
105
|
-
interface Comments extends Resource<Comment> {
|
|
106
|
-
@get list(...CursorPageParameters): CursorPage<Comment>;
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Add `@useAuth(JanusAuth)` on the interface to protect all five, and name the
|
|
111
|
-
guards' replies in the operations you declare again
|
|
112
|
-
([Authentication](auth.md)).
|
package/lib/resources.tsp
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import "@typespec/http";
|
|
2
|
-
|
|
3
|
-
using Http;
|
|
4
|
-
|
|
5
|
-
namespace Nxgt;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* The sort of a list, as `@nxgt/drizzle` takes it: one field, and a
|
|
9
|
-
* direction. `Field` is the union of the fields a client may sort by.
|
|
10
|
-
* Spread it into an operation's parameters.
|
|
11
|
-
*/
|
|
12
|
-
model SortParameters<Field extends string> {
|
|
13
|
-
/** The field to sort by. */
|
|
14
|
-
@query
|
|
15
|
-
orderBy?: Field;
|
|
16
|
-
|
|
17
|
-
/** `asc` or `desc`. */
|
|
18
|
-
@query
|
|
19
|
-
direction?: "asc" | "desc" = "asc";
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* The five operations of a resource, at `/<route>` and `/<route>/{id}`:
|
|
24
|
-
* `list` pages by offset, with the `Filters` the spec writes and a sort by
|
|
25
|
-
* `SortField`; `read`, `create`, `update` (a merge patch) and `delete`.
|
|
26
|
-
* Extend it with `@route`; `@operationIds` names the operations after the
|
|
27
|
-
* interface that extends it: `listPosts`, `readPosts`…
|
|
28
|
-
*
|
|
29
|
-
* @template Item The resource's model.
|
|
30
|
-
* @template Filters A model of `@query` properties, spread into `list`.
|
|
31
|
-
* @template SortField The fields `list` may sort by; `"id"` by default.
|
|
32
|
-
* @template Id The type of `{id}`; `uuid` by default.
|
|
33
|
-
*/
|
|
34
|
-
@operationIds
|
|
35
|
-
interface Resource<
|
|
36
|
-
Item extends {},
|
|
37
|
-
Filters extends {} = {},
|
|
38
|
-
SortField extends string = "id",
|
|
39
|
-
Id = uuid
|
|
40
|
-
> {
|
|
41
|
-
/** One page of the resources, filtered and sorted. */
|
|
42
|
-
@get
|
|
43
|
-
list(...Filters, ...PageParameters, ...SortParameters<SortField>): Page<Item>;
|
|
44
|
-
|
|
45
|
-
/** One resource. */
|
|
46
|
-
@get
|
|
47
|
-
read(@path id: Id): Item | NotFound;
|
|
48
|
-
|
|
49
|
-
/** Creates a resource. */
|
|
50
|
-
@post
|
|
51
|
-
create(@body item: Create<Item>): {
|
|
52
|
-
@statusCode _: 201;
|
|
53
|
-
@body item: Item;
|
|
54
|
-
} | BadRequest | Conflict;
|
|
55
|
-
|
|
56
|
-
/** Updates a resource with a merge patch. */
|
|
57
|
-
@patch
|
|
58
|
-
update(@path id: Id, @body item: MergePatchUpdate<Item>): Item | BadRequest | NotFound | Conflict;
|
|
59
|
-
|
|
60
|
-
/** Deletes a resource. */
|
|
61
|
-
@delete
|
|
62
|
-
delete(@path id: Id): NoContentResponse | NotFound;
|
|
63
|
-
}
|