@antelopejs/interface-data-api 0.1.9 → 0.2.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/dist/antelope.test.js +4 -3
- package/dist/antelope.test.js.map +1 -1
- package/dist/components.d.ts +39 -8
- package/dist/components.js +106 -28
- package/dist/components.js.map +1 -1
- package/dist/index.d.ts +13 -31
- package/dist/index.js +20 -22
- package/dist/index.js.map +1 -1
- package/dist/metadata.d.ts +43 -6
- package/dist/metadata.js +6 -4
- package/dist/metadata.js.map +1 -1
- package/dist/tests/components/access_control.test.js +2 -2
- package/dist/tests/components/access_control.test.js.map +1 -1
- package/dist/tests/components/computed.test.js +2 -2
- package/dist/tests/components/computed.test.js.map +1 -1
- package/dist/tests/components/deferred_joined.test.js +3 -3
- package/dist/tests/components/deferred_joined.test.js.map +1 -1
- package/dist/tests/components/filter_options.test.js +1 -1
- package/dist/tests/components/filter_options.test.js.map +1 -1
- package/dist/tests/components/foreign_joined.test.js +2 -2
- package/dist/tests/components/foreign_joined.test.js.map +1 -1
- package/dist/tests/components/joined.test.js +3 -3
- package/dist/tests/components/joined.test.js.map +1 -1
- package/dist/tests/components/listable.test.js +2 -2
- package/dist/tests/components/listable.test.js.map +1 -1
- package/dist/tests/components/mandatory.test.js +29 -8
- package/dist/tests/components/mandatory.test.js.map +1 -1
- package/dist/tests/components/modifier_key.test.js +2 -2
- package/dist/tests/components/modifier_key.test.js.map +1 -1
- package/dist/tests/components/parsed_value.test.d.ts +1 -0
- package/dist/tests/components/parsed_value.test.js +152 -0
- package/dist/tests/components/parsed_value.test.js.map +1 -0
- package/dist/tests/components/partial_edit.test.d.ts +1 -0
- package/dist/tests/components/partial_edit.test.js +277 -0
- package/dist/tests/components/partial_edit.test.js.map +1 -0
- package/dist/tests/components/per_action_access.test.js +1 -1
- package/dist/tests/components/per_action_access.test.js.map +1 -1
- package/dist/tests/components/validator.test.js +1 -1
- package/dist/tests/components/validator.test.js.map +1 -1
- package/dist/tests/index/get_guard.test.js +2 -2
- package/dist/tests/index/get_guard.test.js.map +1 -1
- package/dist/tests/index/inheritance.test.d.ts +1 -0
- package/dist/tests/index/inheritance.test.js +122 -0
- package/dist/tests/index/inheritance.test.js.map +1 -0
- package/dist/tests/index/routes.test.js +2 -2
- package/dist/tests/index/routes.test.js.map +1 -1
- package/dist/tests/integration.test.js +1 -1
- package/dist/tests/integration.test.js.map +1 -1
- package/dist/tests/utils.d.ts +7 -0
- package/dist/tests/utils.js +48 -6
- package/dist/tests/utils.js.map +1 -1
- package/dist/tests/utils.test.d.ts +1 -0
- package/dist/tests/utils.test.js +28 -0
- package/dist/tests/utils.test.js.map +1 -0
- package/docs/1.introduction.md +7 -7
- package/docs/10.joined.md +13 -13
- package/docs/11.computed.md +11 -15
- package/docs/2.data-controllers.md +5 -5
- package/docs/3.routes.md +61 -49
- package/docs/4.access-rights.md +5 -5
- package/docs/5.validators.md +29 -8
- package/docs/6.listable.md +7 -7
- package/docs/7.foreign-keys.md +7 -7
- package/docs/8.filters.md +16 -16
- package/docs/9.modifiers.md +2 -2
- package/package.json +44 -36
- package/skills/data-api-interface/SKILL.md +58 -8
package/docs/5.validators.md
CHANGED
|
@@ -8,7 +8,7 @@ Validators provide field-level data integrity checks that run automatically duri
|
|
|
8
8
|
|
|
9
9
|
### Basic Usage
|
|
10
10
|
|
|
11
|
-
The `@Validator` decorator accepts a function that receives the field value and returns `true` if valid or `false` if invalid. The function can also return a `Promise
|
|
11
|
+
The `@Validator` decorator accepts a function that receives the field value and returns `true` if valid or `false` if invalid. It can instead return a parse result (see [Parsed Values](#parsed-values)) so that the parsed value is written. The function can also return a `Promise` of either for asynchronous validation.
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
14
|
import { Validator } from "@antelopejs/interface-data-api/metadata";
|
|
@@ -36,16 +36,34 @@ class UserAPI extends DataController(
|
|
|
36
36
|
### Validation Function Signature
|
|
37
37
|
|
|
38
38
|
```typescript
|
|
39
|
-
type
|
|
39
|
+
type FieldValidator = (
|
|
40
|
+
value: unknown,
|
|
41
|
+
) => FieldValidationResult | Promise<FieldValidationResult>;
|
|
42
|
+
|
|
43
|
+
type FieldValidationResult =
|
|
44
|
+
boolean | { success: true; data: unknown } | { success: false };
|
|
40
45
|
```
|
|
41
46
|
|
|
42
47
|
The function:
|
|
43
48
|
|
|
44
49
|
- Receives the raw field value from the request body.
|
|
45
|
-
- Returns `true` when the value is valid.
|
|
46
|
-
- Returns `
|
|
50
|
+
- Returns `true` when the value is valid: the raw value is written.
|
|
51
|
+
- Returns `{ success: true, data }` when the value is valid: `data` is written instead of the raw value.
|
|
52
|
+
- Returns `false` or `{ success: false }` when the value is invalid, which triggers a `400 Bad Request` response.
|
|
47
53
|
- Should handle unexpected types gracefully (e.g., check `typeof` before accessing properties).
|
|
48
54
|
|
|
55
|
+
### Parsed Values
|
|
56
|
+
|
|
57
|
+
A validator returning a parse result writes the parsed value on both `new` and `edit`. The result has the shape of zod's `safeParse`, so a zod schema can be used directly:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const startsAtSchema = z.coerce.date();
|
|
61
|
+
|
|
62
|
+
@Access(AccessMode.ReadWrite)
|
|
63
|
+
@Validator((value) => startsAtSchema.safeParseAsync(value))
|
|
64
|
+
declare startsAt: Date; // "2026-01-15" is stored as a Date
|
|
65
|
+
```
|
|
66
|
+
|
|
49
67
|
## Common Validation Patterns
|
|
50
68
|
|
|
51
69
|
### String Validation
|
|
@@ -112,7 +130,10 @@ declare email: string;
|
|
|
112
130
|
|
|
113
131
|
## The `@Mandatory` Decorator
|
|
114
132
|
|
|
115
|
-
The `@Mandatory` decorator specifies which operations require a field
|
|
133
|
+
The `@Mandatory` decorator specifies which operations require a field in the request body. Unlike `@Validator`, which checks field content, `@Mandatory` only verifies that the field is provided:
|
|
134
|
+
|
|
135
|
+
- On `"edit"`, the body only carries the fields to update: a mandatory field absent from the body keeps its stored value and is accepted, while a mandatory field cleared by the body (`null`, `""` or `[]`) is rejected.
|
|
136
|
+
- On any other operation (such as `"new"`), a mandatory field must be present in the body.
|
|
116
137
|
|
|
117
138
|
```typescript
|
|
118
139
|
import { Mandatory } from "@antelopejs/interface-data-api/metadata";
|
|
@@ -152,9 +173,9 @@ class UserAPI extends DataController(
|
|
|
152
173
|
|
|
153
174
|
In this example:
|
|
154
175
|
|
|
155
|
-
- `email` must be provided
|
|
176
|
+
- `email` must be provided when creating a record and cannot be cleared when editing one.
|
|
156
177
|
- `password` is required only when creating a new record.
|
|
157
|
-
- `status`
|
|
178
|
+
- `status` cannot be cleared when editing an existing record.
|
|
158
179
|
- `notes` is always optional.
|
|
159
180
|
|
|
160
181
|
### Skip Mandatory Validation
|
|
@@ -177,7 +198,7 @@ class UserAPI extends DataController(User, routes, Controller("/users")) {
|
|
|
177
198
|
}
|
|
178
199
|
```
|
|
179
200
|
|
|
180
|
-
Requests to `/users/edit`
|
|
201
|
+
Requests to `/users/edit` cannot clear `status`, while requests to `/users/patchEdit` can.
|
|
181
202
|
|
|
182
203
|
## The `@Optional` Decorator
|
|
183
204
|
|
package/docs/6.listable.md
CHANGED
|
@@ -140,10 +140,10 @@ List responses include pagination metadata. The response structure is:
|
|
|
140
140
|
|
|
141
141
|
### Query Parameters
|
|
142
142
|
|
|
143
|
-
| Parameter | Default | Description
|
|
144
|
-
| --------- | ------- |
|
|
145
|
-
| `limit`
|
|
146
|
-
| `offset`
|
|
143
|
+
| Parameter | Default | Description |
|
|
144
|
+
| --------- | ------- | ----------------------------------- |
|
|
145
|
+
| `limit` | `10` | Maximum number of records to return |
|
|
146
|
+
| `offset` | `0` | Number of records to skip |
|
|
147
147
|
|
|
148
148
|
### Example
|
|
149
149
|
|
|
@@ -214,9 +214,9 @@ class UserAPI extends DataController(
|
|
|
214
214
|
|
|
215
215
|
### Sort Query Parameters
|
|
216
216
|
|
|
217
|
-
| Parameter
|
|
218
|
-
|
|
|
219
|
-
| `sortKey`
|
|
217
|
+
| Parameter | Description |
|
|
218
|
+
| --------------- | ------------------------------------------------------------------ |
|
|
219
|
+
| `sortKey` | The field name to sort by. Must be decorated with `@Sortable`. |
|
|
220
220
|
| `sortDirection` | `"asc"` (ascending) or `"desc"` (descending). Defaults to `"asc"`. |
|
|
221
221
|
|
|
222
222
|
### The `noIndex` Option
|
package/docs/7.foreign-keys.md
CHANGED
|
@@ -90,13 +90,13 @@ A GET request to `/orders/get?id=order-123` returns the full user object instead
|
|
|
90
90
|
@Foreign(table, index?, multi?, pluck?, schema?)
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
| Parameter | Type
|
|
94
|
-
| --------- |
|
|
95
|
-
| `table`
|
|
96
|
-
| `index`
|
|
97
|
-
| `multi`
|
|
98
|
-
| `pluck`
|
|
99
|
-
| `schema`
|
|
93
|
+
| Parameter | Type | Required | Default | Description |
|
|
94
|
+
| --------- | -------------------------- | -------- | ----------------- | -------------------------------------------------------------------------------------------------- |
|
|
95
|
+
| `table` | `Class<Table>` or `string` | Yes | - | The target table class or table name string |
|
|
96
|
+
| `index` | `string` | No | `"_id"` | The index on the target table to match against |
|
|
97
|
+
| `multi` | `boolean` | No | `false` | Set to `true` when the field holds an array of foreign keys |
|
|
98
|
+
| `pluck` | `string[]` | No | All fields | List of fields to include from the referenced record |
|
|
99
|
+
| `schema` | `string` | No | Controller schema | Name of the schema the target table is registered in, when it differs from the controller's schema |
|
|
100
100
|
|
|
101
101
|
## Table Reference Methods
|
|
102
102
|
|
package/docs/8.filters.md
CHANGED
|
@@ -52,14 +52,14 @@ When no operator is specified, `eq` (equal) is used by default.
|
|
|
52
52
|
|
|
53
53
|
### Comparison Operators
|
|
54
54
|
|
|
55
|
-
| Operator | Description
|
|
56
|
-
| -------- |
|
|
57
|
-
| `eq`
|
|
58
|
-
| `ne`
|
|
59
|
-
| `gt`
|
|
60
|
-
| `ge`
|
|
61
|
-
| `lt`
|
|
62
|
-
| `le`
|
|
55
|
+
| Operator | Description |
|
|
56
|
+
| -------- | ------------------------ |
|
|
57
|
+
| `eq` | Equal to (default) |
|
|
58
|
+
| `ne` | Not equal to |
|
|
59
|
+
| `gt` | Greater than |
|
|
60
|
+
| `ge` | Greater than or equal to |
|
|
61
|
+
| `lt` | Less than |
|
|
62
|
+
| `le` | Less than or equal to |
|
|
63
63
|
|
|
64
64
|
### Examples
|
|
65
65
|
|
|
@@ -98,14 +98,14 @@ type FilterFunction<T, U> = (
|
|
|
98
98
|
) => ValueProxyOrValue<boolean>;
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
| Parameter | Description
|
|
102
|
-
| --------- |
|
|
103
|
-
| `context` | The request context, extended with `this` referencing the controller instance
|
|
104
|
-
| `proxy`
|
|
105
|
-
| `key`
|
|
106
|
-
| `value`
|
|
107
|
-
| `mode`
|
|
108
|
-
| `row`
|
|
101
|
+
| Parameter | Description |
|
|
102
|
+
| --------- | -------------------------------------------------------------------------------------------------------------- |
|
|
103
|
+
| `context` | The request context, extended with `this` referencing the controller instance |
|
|
104
|
+
| `proxy` | A `ValueProxy` representing the field value with modifier transformations applied (e.g., decrypted, localized) |
|
|
105
|
+
| `key` | The field name being filtered |
|
|
106
|
+
| `value` | The filter value from the query parameter |
|
|
107
|
+
| `mode` | The comparison operator from the query parameter |
|
|
108
|
+
| `row` | The full database row as a `ValueProxy` |
|
|
109
109
|
|
|
110
110
|
### Example: Pattern Matching Filter
|
|
111
111
|
|
package/docs/9.modifiers.md
CHANGED
|
@@ -20,8 +20,8 @@ import { ModifierKey } from "@antelopejs/interface-data-api/metadata";
|
|
|
20
20
|
@ModifierKey(modifierClass: typeof ContainerModifier<any>)
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
| Parameter
|
|
24
|
-
|
|
|
23
|
+
| Parameter | Description |
|
|
24
|
+
| --------------- | ----------------------------------------------------------------------------- |
|
|
25
25
|
| `modifierClass` | The modifier class that requires a runtime key (e.g., `LocalizationModifier`) |
|
|
26
26
|
|
|
27
27
|
### Example: Localized Content
|
package/package.json
CHANGED
|
@@ -1,26 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/interface-data-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "AntelopeJS interface for data API with CRUD controllers and route generation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelopejs",
|
|
7
|
-
"
|
|
7
|
+
"crud",
|
|
8
8
|
"data-api",
|
|
9
|
-
"
|
|
9
|
+
"interface"
|
|
10
10
|
],
|
|
11
|
+
"license": "Apache-2.0",
|
|
11
12
|
"repository": {
|
|
12
13
|
"type": "git",
|
|
13
14
|
"url": "git+https://github.com/AntelopeJS/interface-data-api.git"
|
|
14
15
|
},
|
|
15
|
-
"license": "Apache-2.0",
|
|
16
|
-
"packageManager": "pnpm@10.6.5",
|
|
17
|
-
"main": "dist/index.js",
|
|
18
|
-
"types": "dist/index.d.ts",
|
|
19
16
|
"files": [
|
|
20
17
|
"dist",
|
|
21
18
|
"docs",
|
|
22
19
|
"skills"
|
|
23
20
|
],
|
|
21
|
+
"main": "dist/index.js",
|
|
22
|
+
"types": "dist/index.d.ts",
|
|
23
|
+
"typesVersions": {
|
|
24
|
+
"*": {
|
|
25
|
+
"components": [
|
|
26
|
+
"dist/components.d.ts"
|
|
27
|
+
],
|
|
28
|
+
"metadata": [
|
|
29
|
+
"dist/metadata.d.ts"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
24
33
|
"exports": {
|
|
25
34
|
".": {
|
|
26
35
|
"types": "./dist/index.d.ts",
|
|
@@ -32,54 +41,53 @@
|
|
|
32
41
|
},
|
|
33
42
|
"./package.json": "./package.json"
|
|
34
43
|
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public",
|
|
46
|
+
"provenance": true
|
|
47
|
+
},
|
|
35
48
|
"scripts": {
|
|
36
49
|
"build": "rimraf dist && tsc",
|
|
37
|
-
"format": "
|
|
38
|
-
"lint:fix": "
|
|
39
|
-
"lint": "
|
|
50
|
+
"format": "oxfmt .",
|
|
51
|
+
"lint:fix": "oxlint --fix",
|
|
52
|
+
"lint": "oxlint",
|
|
40
53
|
"prepack": "pnpm run build",
|
|
41
54
|
"release": "pnpm run lint && pnpm run prepack && release-it",
|
|
42
|
-
"test": "pnpm run build && ajs module test ."
|
|
55
|
+
"test": "pnpm run build && ajs module test .",
|
|
56
|
+
"format:check": "oxfmt --check .",
|
|
57
|
+
"knip": "knip"
|
|
43
58
|
},
|
|
44
59
|
"devDependencies": {
|
|
45
|
-
"@antelopejs/
|
|
46
|
-
"@antelopejs/interface-api
|
|
47
|
-
"@antelopejs/interface-
|
|
48
|
-
"@antelopejs/interface-
|
|
49
|
-
"@antelopejs/interface-database
|
|
50
|
-
"@
|
|
60
|
+
"@antelopejs/core": "^1.13.4",
|
|
61
|
+
"@antelopejs/interface-api": "^0.0.13",
|
|
62
|
+
"@antelopejs/interface-api-util": "^0.1.2",
|
|
63
|
+
"@antelopejs/interface-core": "^0.1.1",
|
|
64
|
+
"@antelopejs/interface-database": "^0.1.7",
|
|
65
|
+
"@antelopejs/interface-database-decorators": "^0.1.6",
|
|
66
|
+
"@antelopejs/tooling-configs": "^0.0.6",
|
|
51
67
|
"@types/chai": "^4.3.20",
|
|
52
68
|
"@types/mocha": "^10.0.10",
|
|
53
69
|
"@types/node": "^22.19.15",
|
|
54
70
|
"@types/semver": "^7.7.1",
|
|
55
71
|
"chai": "^4.5.0",
|
|
72
|
+
"eslint-plugin-perfectionist": "^5.11.0",
|
|
73
|
+
"knip": "^6.34.0",
|
|
56
74
|
"mongodb-memory-server-core": "^10.4.3",
|
|
75
|
+
"oxfmt": "^0.66.0",
|
|
76
|
+
"oxlint": "1.81.0",
|
|
77
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
57
78
|
"release-it": "^19.2.4",
|
|
58
79
|
"release-it-changelogen": "^0.1.0",
|
|
59
80
|
"rimraf": "^6.1.3",
|
|
60
81
|
"typescript": "^5.9.3"
|
|
61
82
|
},
|
|
62
83
|
"peerDependencies": {
|
|
63
|
-
"@antelopejs/interface-api": ">=0.0.
|
|
64
|
-
"@antelopejs/interface-api-util": ">=0.
|
|
65
|
-
"@antelopejs/interface-core": ">=0.
|
|
66
|
-
"@antelopejs/interface-database": ">=0.1.
|
|
67
|
-
"@antelopejs/interface-database-decorators": ">=0.1.
|
|
68
|
-
},
|
|
69
|
-
"publishConfig": {
|
|
70
|
-
"access": "public",
|
|
71
|
-
"provenance": true
|
|
72
|
-
},
|
|
73
|
-
"typesVersions": {
|
|
74
|
-
"*": {
|
|
75
|
-
"components": [
|
|
76
|
-
"dist/components.d.ts"
|
|
77
|
-
],
|
|
78
|
-
"metadata": [
|
|
79
|
-
"dist/metadata.d.ts"
|
|
80
|
-
]
|
|
81
|
-
}
|
|
84
|
+
"@antelopejs/interface-api": ">=0.0.13 <1.0.0",
|
|
85
|
+
"@antelopejs/interface-api-util": ">=0.1.2 <1.0.0",
|
|
86
|
+
"@antelopejs/interface-core": ">=0.1.1 <1.0.0",
|
|
87
|
+
"@antelopejs/interface-database": ">=0.1.7 <1.0.0",
|
|
88
|
+
"@antelopejs/interface-database-decorators": ">=0.1.6 <1.0.0"
|
|
82
89
|
},
|
|
90
|
+
"packageManager": "pnpm@10.6.5",
|
|
83
91
|
"antelopeJs": {
|
|
84
92
|
"standalone": true,
|
|
85
93
|
"test": "src/antelope.test.ts",
|
|
@@ -17,9 +17,32 @@ your module must also import those peer interfaces.
|
|
|
17
17
|
## Imports
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
import {
|
|
21
|
+
DataController,
|
|
22
|
+
DefaultRoutes,
|
|
23
|
+
RegisterDataController,
|
|
24
|
+
GetDataControllerMeta,
|
|
25
|
+
} from "@antelopejs/interface-data-api";
|
|
26
|
+
import {
|
|
27
|
+
Access,
|
|
28
|
+
AccessMode,
|
|
29
|
+
Listable,
|
|
30
|
+
Mandatory,
|
|
31
|
+
Optional,
|
|
32
|
+
Sortable,
|
|
33
|
+
Filter,
|
|
34
|
+
Foreign,
|
|
35
|
+
Joined,
|
|
36
|
+
Computed,
|
|
37
|
+
Validator,
|
|
38
|
+
ModelReference,
|
|
39
|
+
ModifierKey,
|
|
40
|
+
} from "@antelopejs/interface-data-api/metadata";
|
|
41
|
+
import {
|
|
42
|
+
Parameters,
|
|
43
|
+
Query,
|
|
44
|
+
Validation,
|
|
45
|
+
} from "@antelopejs/interface-data-api/components";
|
|
23
46
|
```
|
|
24
47
|
|
|
25
48
|
`/components` is only needed for custom route callbacks (query building, validation helpers).
|
|
@@ -28,9 +51,26 @@ import { Parameters, Query, Validation } from "@antelopejs/interface-data-api/co
|
|
|
28
51
|
|
|
29
52
|
```typescript
|
|
30
53
|
import { Controller } from "@antelopejs/interface-api";
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
54
|
+
import {
|
|
55
|
+
DataController,
|
|
56
|
+
DefaultRoutes,
|
|
57
|
+
RegisterDataController,
|
|
58
|
+
} from "@antelopejs/interface-data-api";
|
|
59
|
+
import {
|
|
60
|
+
Access,
|
|
61
|
+
AccessMode,
|
|
62
|
+
Listable,
|
|
63
|
+
Mandatory,
|
|
64
|
+
ModelReference,
|
|
65
|
+
Sortable,
|
|
66
|
+
} from "@antelopejs/interface-data-api/metadata";
|
|
67
|
+
import {
|
|
68
|
+
BasicDataModel,
|
|
69
|
+
Field,
|
|
70
|
+
Model,
|
|
71
|
+
RegisterTable,
|
|
72
|
+
Table,
|
|
73
|
+
} from "@antelopejs/interface-database-decorators";
|
|
34
74
|
|
|
35
75
|
@RegisterTable("tasks", "default")
|
|
36
76
|
class Task extends Table {
|
|
@@ -43,7 +83,11 @@ class Task extends Table {
|
|
|
43
83
|
class TaskModel extends BasicDataModel(Task, "tasks") {}
|
|
44
84
|
|
|
45
85
|
@RegisterDataController()
|
|
46
|
-
class TaskAPI extends DataController(
|
|
86
|
+
class TaskAPI extends DataController(
|
|
87
|
+
Task,
|
|
88
|
+
DefaultRoutes.All,
|
|
89
|
+
Controller("/tasks"),
|
|
90
|
+
) {
|
|
47
91
|
@ModelReference()
|
|
48
92
|
@Model(TaskModel, "my-database")
|
|
49
93
|
declare taskModel: TaskModel;
|
|
@@ -67,7 +111,8 @@ This exposes `GET /tasks/get?id=`, `GET /tasks/list`, `POST /tasks/new`, `PUT /t
|
|
|
67
111
|
|
|
68
112
|
- `@RegisterDataController()` is mandatory: it wires field decorators, parameter providers, and
|
|
69
113
|
routes. A `@ModelReference()` property holding a `@Model` instance is required too (`Query.GetModel`
|
|
70
|
-
throws 500 without it).
|
|
114
|
+
throws 500 without it). A controller derived from another data controller inherits it unless it
|
|
115
|
+
declares its own.
|
|
71
116
|
- Fields with no decorator are invisible to the API — neither returned nor writable; visibility
|
|
72
117
|
requires `@Access`. `@Optional()` only registers a field as not-mandatory (it does not expose it).
|
|
73
118
|
- `list` responds `{ results, total, offset, limit }`. `limit` defaults to 10 and is capped at 100
|
|
@@ -83,6 +128,11 @@ This exposes `GET /tasks/get?id=`, `GET /tasks/list`, `POST /tasks/new`, `PUT /t
|
|
|
83
128
|
of `DefaultRoutes.All`; use `DefaultRoutes.WithOptions(route, options, endpoint)` to rename an
|
|
84
129
|
endpoint or preset parameter options.
|
|
85
130
|
- `@Access` accepts per-action overrides, e.g. `@Access(AccessMode.ReadOnly, { edit: AccessMode.ReadWrite })`.
|
|
131
|
+
- `edit` is a partial update: a field absent from the body is left unchanged, `null` clears it, and
|
|
132
|
+
setters only run for the fields present. `@Mandatory("edit")` rejects a field cleared by the body
|
|
133
|
+
(`null`, `""`, `[]`), not an absent one. `new` still writes every writable field and runs every setter.
|
|
134
|
+
- A `@Validator` may return a parse result `{ success, data }` (e.g. zod's `safeParseAsync(value)`)
|
|
135
|
+
instead of a boolean: `data` is then written in place of the raw value.
|
|
86
136
|
|
|
87
137
|
## Deeper reference
|
|
88
138
|
|