@kollors/deep-json-server 1.0.0-alpha.1 → 1.0.0-alpha.3
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 +104 -53
- package/README.ru.md +103 -50
- package/dist/index.d.ts +5 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/src/cli.d.ts +2 -2
- package/dist/src/cli.js +97 -48
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.d.ts +14 -1
- package/dist/src/config.js +56 -8
- package/dist/src/config.js.map +1 -1
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/constants.js +1 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/database.d.ts +0 -1
- package/dist/src/database.js +12 -10
- package/dist/src/database.js.map +1 -1
- package/dist/src/engine.d.ts +21 -10
- package/dist/src/engine.js +77 -144
- package/dist/src/engine.js.map +1 -1
- package/dist/src/errors.d.ts +6 -0
- package/dist/src/errors.js +9 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/features.d.ts +8 -0
- package/dist/src/features.js +18 -0
- package/dist/src/features.js.map +1 -0
- package/dist/src/files/contract.d.ts +0 -30
- package/dist/src/files/contract.js +6 -47
- package/dist/src/files/contract.js.map +1 -1
- package/dist/src/files/disk-store.d.ts +2 -1
- package/dist/src/files/disk-store.js +28 -18
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/files/http.d.ts +31 -0
- package/dist/src/files/http.js +44 -0
- package/dist/src/files/http.js.map +1 -0
- package/dist/src/files/index.d.ts +1 -1
- package/dist/src/files/index.js +1 -1
- package/dist/src/files/index.js.map +1 -1
- package/dist/src/files/memory-store.js +8 -7
- package/dist/src/files/memory-store.js.map +1 -1
- package/dist/src/files/openapi.js +2 -4
- package/dist/src/files/openapi.js.map +1 -1
- package/dist/src/files/routes.js +3 -2
- package/dist/src/files/routes.js.map +1 -1
- package/dist/src/graphql/entry.d.ts +3 -0
- package/dist/src/graphql/entry.js +3 -0
- package/dist/src/graphql/entry.js.map +1 -0
- package/dist/src/graphql/preflight.d.ts +3 -0
- package/dist/src/graphql/preflight.js +30 -0
- package/dist/src/graphql/preflight.js.map +1 -0
- package/dist/src/graphql/public.d.ts +3 -0
- package/dist/src/graphql/public.js +11 -0
- package/dist/src/graphql/public.js.map +1 -0
- package/dist/src/graphql/resolvers.d.ts +8 -0
- package/dist/src/graphql/resolvers.js +38 -0
- package/dist/src/graphql/resolvers.js.map +1 -0
- package/dist/src/graphql/routes.d.ts +4 -0
- package/dist/src/graphql/routes.js +27 -0
- package/dist/src/graphql/routes.js.map +1 -0
- package/dist/src/graphql/write.d.ts +1 -0
- package/dist/src/graphql/write.js +7 -0
- package/dist/src/graphql/write.js.map +1 -0
- package/dist/src/graphql.d.ts +1 -2
- package/dist/src/graphql.js +24 -34
- package/dist/src/graphql.js.map +1 -1
- package/dist/src/http/errors.d.ts +6 -0
- package/dist/src/http/errors.js +3 -0
- package/dist/src/http/errors.js.map +1 -0
- package/dist/src/model.d.ts +2 -3
- package/dist/src/model.js +54 -12
- package/dist/src/model.js.map +1 -1
- package/dist/src/openapi/document.js +36 -29
- package/dist/src/openapi/document.js.map +1 -1
- package/dist/src/openapi/entry.d.ts +3 -0
- package/dist/src/openapi/entry.js +2 -0
- package/dist/src/openapi/entry.js.map +1 -0
- package/dist/src/openapi/helpers.d.ts +17 -0
- package/dist/src/openapi/helpers.js +4 -0
- package/dist/src/openapi/helpers.js.map +1 -0
- package/dist/src/openapi/index.js +6 -4
- package/dist/src/openapi/index.js.map +1 -1
- package/dist/src/openapi/public.d.ts +17 -0
- package/dist/src/openapi/public.js +18 -0
- package/dist/src/openapi/public.js.map +1 -0
- package/dist/src/pagination.d.ts +7 -0
- package/dist/src/pagination.js +12 -0
- package/dist/src/pagination.js.map +1 -0
- package/dist/src/paths.d.ts +6 -0
- package/dist/src/paths.js +47 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/query/contract.d.ts +3 -0
- package/dist/src/query/contract.js +19 -0
- package/dist/src/query/contract.js.map +1 -0
- package/dist/src/query/filter.d.ts +3 -1
- package/dist/src/query/filter.js +78 -76
- package/dist/src/query/filter.js.map +1 -1
- package/dist/src/query/options.d.ts +1 -14
- package/dist/src/query/options.js +6 -109
- package/dist/src/query/options.js.map +1 -1
- package/dist/src/relation-metadata.d.ts +0 -1
- package/dist/src/relation-metadata.js +0 -1
- package/dist/src/relation-metadata.js.map +1 -1
- package/dist/src/rest/options.d.ts +14 -0
- package/dist/src/rest/options.js +108 -0
- package/dist/src/rest/options.js.map +1 -0
- package/dist/src/rest/projection.d.ts +6 -0
- package/dist/src/rest/projection.js +38 -0
- package/dist/src/rest/projection.js.map +1 -0
- package/dist/src/rest/routes.d.ts +3 -0
- package/dist/src/rest/routes.js +48 -0
- package/dist/src/rest/routes.js.map +1 -0
- package/dist/src/schema.d.ts +8 -0
- package/dist/src/schema.js +13 -0
- package/dist/src/schema.js.map +1 -0
- package/dist/src/server/public.d.ts +3 -0
- package/dist/src/server/public.js +2 -0
- package/dist/src/server/public.js.map +1 -0
- package/dist/src/server.d.ts +5 -7
- package/dist/src/server.js +86 -143
- package/dist/src/server.js.map +1 -1
- package/dist/src/utils.d.ts +0 -7
- package/dist/src/utils.js +0 -4
- package/dist/src/utils.js.map +1 -1
- package/package.json +13 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A JSON-backed mock server with REST, GraphQL, nested queries, binary files and schema exports. Requires Node.js 22 or newer.
|
|
6
6
|
|
|
7
|
-
**1.0.0-alpha.
|
|
7
|
+
**1.0.0-alpha.3 is a prerelease.** When upgrading from 0.x, update your model schema and query parameters using the examples below.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -12,29 +12,35 @@ A JSON-backed mock server with REST, GraphQL, nested queries, binary files and s
|
|
|
12
12
|
npm install @kollors/deep-json-server@alpha
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
To install a specific version, use `@1.0.0-alpha.3`.
|
|
16
16
|
|
|
17
17
|
## Quick start
|
|
18
18
|
|
|
19
|
+
Create two files in the same directory.
|
|
20
|
+
|
|
21
|
+
`database.json`:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"users": [
|
|
26
|
+
{ "id": "1", "fullName": "Мира Волкова" }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
19
31
|
`server.config.js`:
|
|
20
32
|
|
|
21
33
|
```js
|
|
22
34
|
export default {
|
|
23
|
-
database: { path: './database.json'
|
|
24
|
-
graphql: { enabled: true, path: './generated/schema.graphql' },
|
|
25
|
-
openapi: { path: './generated/openapi.yaml' },
|
|
26
|
-
server: { host: '127.0.0.1', port: 4001, pageSize: 10, maxPageSize: 100 },
|
|
35
|
+
database: { path: './database.json' },
|
|
27
36
|
};
|
|
28
37
|
```
|
|
29
38
|
|
|
30
39
|
```sh
|
|
31
40
|
npx deep-json-server server.config.js
|
|
32
|
-
npx deep-json-server --openapi-only --graphql-only server.config.js
|
|
33
41
|
```
|
|
34
42
|
|
|
35
|
-
The
|
|
36
|
-
|
|
37
|
-
Complete catalog examples: [database](examples/database.json), [model schema](examples/schema.json), [configuration](examples/server.config.js).
|
|
43
|
+
The user list is available at `http://127.0.0.1:4001/users`.
|
|
38
44
|
|
|
39
45
|
## Configuration
|
|
40
46
|
|
|
@@ -42,8 +48,10 @@ Complete catalog examples: [database](examples/database.json), [model schema](ex
|
|
|
42
48
|
|---|---|
|
|
43
49
|
| `database.path` / `database.data` | Exactly one: JSON file or in-memory collection object |
|
|
44
50
|
| `database.schema` | Model object or JSON schema-file path; optional for REST |
|
|
51
|
+
| `openapi.enabled` | Enable the specification endpoint; default `false` |
|
|
52
|
+
| `openapi.endpoint` | Specification path; default `/openapi.json` |
|
|
45
53
|
| `openapi.path` | YAML export destination |
|
|
46
|
-
| `openapi.info` | Optional `title
|
|
54
|
+
| `openapi.info` | Optional metadata object: required `title` and `version`, optional `description` |
|
|
47
55
|
| `graphql.enabled` | Enable GraphQL HTTP endpoint; default `false` |
|
|
48
56
|
| `graphql.endpoint` | Endpoint path; default `/graphql` |
|
|
49
57
|
| `graphql.path` | GraphQL SDL export destination |
|
|
@@ -54,24 +62,46 @@ Complete catalog examples: [database](examples/database.json), [model schema](ex
|
|
|
54
62
|
| `files.data` | In-memory binary files |
|
|
55
63
|
| `files.directory`, `files.metadata` | Disk storage directory and metadata JSON file; both required |
|
|
56
64
|
|
|
57
|
-
|
|
65
|
+
Relative paths resolve from the configuration file's directory. When passing a configuration object to `createServer()`, paths resolve from the working directory. The server works with a copy of in-memory input and metadata.
|
|
58
66
|
|
|
59
|
-
|
|
67
|
+
Set `server.port` to `0` to let the operating system choose an available port. The OpenAPI endpoint uses a relative server URL.
|
|
60
68
|
|
|
61
|
-
|
|
|
69
|
+
| CLI flag | Action |
|
|
62
70
|
|---|---|
|
|
63
|
-
| `--files` | Enable
|
|
64
|
-
| `--graphql` | Enable GraphQL
|
|
65
|
-
| `--openapi` |
|
|
66
|
-
| `--
|
|
67
|
-
| `--
|
|
68
|
-
| `--
|
|
69
|
-
| `--
|
|
71
|
+
| `--files` | Enable file routes |
|
|
72
|
+
| `--graphql` | Enable the GraphQL API |
|
|
73
|
+
| `--openapi` | Enable the OpenAPI endpoint |
|
|
74
|
+
| `--host <host>` | Server address |
|
|
75
|
+
| `--port <port>` | Server port |
|
|
76
|
+
| `--help`, `-h` | Show help |
|
|
77
|
+
| `--version`, `-v` | Show package version |
|
|
78
|
+
|
|
79
|
+
Setting priority: CLI → configuration → `HOST`/`PORT` → defaults. File routes are enabled when `files` is configured.
|
|
80
|
+
|
|
81
|
+
To generate schemas, specify the format and configuration file:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
npx deep-json-server generate openapi server.config.js
|
|
85
|
+
npx deep-json-server generate graphql server.config.js
|
|
86
|
+
npx deep-json-server generate openapi,graphql server.config.js
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The command reads `database.schema` and writes schemas to `openapi.path` and `graphql.path`. A configuration for generation only can contain:
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
export default {
|
|
93
|
+
database: { schema: './schema.json' },
|
|
94
|
+
openapi: { path: './generated/openapi.yaml' },
|
|
95
|
+
graphql: { path: './generated/schema.graphql' },
|
|
96
|
+
};
|
|
97
|
+
```
|
|
70
98
|
|
|
71
|
-
|
|
99
|
+
Each format needs its own output file. The command rejects destinations that would overwrite the configuration, database, schema or file metadata.
|
|
72
100
|
|
|
73
101
|
## Model schema
|
|
74
102
|
|
|
103
|
+
Examples: [database](examples/database.json), [model schema](examples/schema.json), [configuration](examples/server.config.js).
|
|
104
|
+
|
|
75
105
|
```json
|
|
76
106
|
{
|
|
77
107
|
"Country": {
|
|
@@ -104,11 +134,13 @@ Both exporters can be combined. Any `--*-only` flag prevents startup. CLI file r
|
|
|
104
134
|
| OpenAPI 3.0.3 export | Available | Error when requested |
|
|
105
135
|
| GraphQL SDL / API | Available | Error when requested |
|
|
106
136
|
|
|
107
|
-
Explicit schemas are strict: undeclared fields and collections are rejected, except storage keys inferred from relations. Existing data is validated on startup.
|
|
137
|
+
Explicit schemas are strict: undeclared fields and collections are rejected, except storage keys inferred from relations. Existing data is validated on startup. Generation uses the model definitions.
|
|
138
|
+
|
|
139
|
+
Schemaless REST generates an `id` and preserves arbitrary JSON fields. Filters and individual field selections use identifier-style names; other fields are returned through `scope=*`. Fields with mixed value types can be read, but using them in `where`, `order` or `nested` requires an explicit schema.
|
|
108
140
|
|
|
109
141
|
### Fields
|
|
110
142
|
|
|
111
|
-
|
|
143
|
+
The `type` property accepts `string`, `number`, `boolean`, `object`, or a model name. Append `[]` for an array: `string[]`, `object[]`, `Genre[]`. Use dotted paths for nested fields, such as `actors.fullName`.
|
|
112
144
|
|
|
113
145
|
| Properties | Meaning |
|
|
114
146
|
|---|---|
|
|
@@ -116,7 +148,7 @@ Types: `string`, `number`, `boolean`, `object`, or a model name. Append `[]` for
|
|
|
116
148
|
| `description`, `example` | Documentation and example value |
|
|
117
149
|
| `required`, `nullable` | Defaults `false`; presence and explicit null are separate |
|
|
118
150
|
| `default` | Value when omitted on create/replace; PATCH does not insert defaults |
|
|
119
|
-
| `enum` | Allowed
|
|
151
|
+
| `enum` | Allowed strings, numbers or booleans; for arrays, allowed element values |
|
|
120
152
|
| `primary` | Root primary key; mandatory, unique, non-null and immutable |
|
|
121
153
|
| `generated` | `uuid` for strings, `increment` for numbers; server supplies the value |
|
|
122
154
|
| `readOnly`, `writeOnly` | Output-only or input-only; mutually exclusive |
|
|
@@ -125,11 +157,13 @@ Types: `string`, `number`, `boolean`, `object`, or a model name. Append `[]` for
|
|
|
125
157
|
| `minimum`, `maximum` | Inclusive numeric bounds |
|
|
126
158
|
| `source`, `target`, `onDelete` | Relation metadata |
|
|
127
159
|
|
|
128
|
-
String
|
|
160
|
+
String and numeric constraints on `string[]`/`number[]` apply to every element. `required` and `nullable` apply to the entire array; `default` and `example` contain a complete array. Elements must match the array's type and be non-null. `required` requires the field to be present; an ordinary array may still be empty.
|
|
129
161
|
|
|
130
|
-
|
|
162
|
+
Each model requires exactly one primary key of type `string` or `number`, declared at the top level. The name is arbitrary: `id`, `username`, `code`. If `generated` is omitted, the client supplies the value on creation. Generated fields must be declared at the top level, are excluded from input types and cannot have `default`. Replacing a record preserves generated values and read-only fields, including nested objects. To protect fields inside an array, mark the entire array or its containing object as `readOnly`. Objects containing only server-managed fields are output-only.
|
|
131
163
|
|
|
132
|
-
For example, a `LocalUser` with primary `username` and `password: {"type":"string","required":true,"writeOnly":true}` has `localUser(username: ...)` and `/localUsers/{username}`. `writeOnly`
|
|
164
|
+
For example, a `LocalUser` with primary key `username` and `password: {"type":"string","required":true,"writeOnly":true}` has `localUser(username: ...)` and `/localUsers/{username}`. A `writeOnly` field accepts input and is excluded from responses, `scope`, filters and ordering.
|
|
165
|
+
|
|
166
|
+
Objects used in GraphQL must have at least one field visible in responses; REST also accepts empty objects.
|
|
133
167
|
|
|
134
168
|
### Relations
|
|
135
169
|
|
|
@@ -141,20 +175,20 @@ For example, a `LocalUser` with primary `username` and `password: {"type":"strin
|
|
|
141
175
|
}
|
|
142
176
|
```
|
|
143
177
|
|
|
144
|
-
`Genre`
|
|
178
|
+
`Genre` returns an object; `Genre[]` returns a list. `source` defaults to the current model's primary key, `target` to the target model's primary key. These defaults also apply to nested relations. Paths start at the root of their respective records: in this example, `actors.genreIds` contains the current actor's genre keys.
|
|
145
179
|
|
|
146
|
-
|
|
180
|
+
Relation keys are stored in the database and included among the record's own fields. Their types are inferred from the matched keys. A `source` field pointing to a target primary key can be omitted from the field declarations: the schema infers an array of keys for a list relation or a scalar key for a single relation. Declare the storage field explicitly when the mapping is ambiguous.
|
|
147
181
|
|
|
148
182
|
Reverse example: `User.movies = {"type":"Movie[]","target":"actors.userId"}`. A movie is returned once even if several actors match. A single relation resolving to multiple targets is invalid.
|
|
149
183
|
|
|
150
|
-
Every supplied direct
|
|
184
|
+
Every supplied direct relation key must point to an existing record. `required: true` on a relation requires at least one target before response filtering/pagination. Reverse relations using the primary key as `source` may be empty unless required. Missing single relations return `null`.
|
|
151
185
|
|
|
152
186
|
`onDelete` describes what happens **when a target record is deleted**:
|
|
153
187
|
|
|
154
188
|
- `restrict` (default): refuse deletion while a surviving owner refers to the target.
|
|
155
189
|
- `cascade`: delete the referring owner. For `User.country`, deleting the country deletes its users. For `Movie.actors.user`, deleting the user removes matching actor elements and retains the movie.
|
|
156
190
|
|
|
157
|
-
|
|
191
|
+
Cascading deletion runs as one operation, including cyclic relations. A validation failure cancels the entire operation. `onDelete` rules also apply to explicitly declared reverse relations; account for both rules when defining both directions.
|
|
158
192
|
|
|
159
193
|
## Queries and responses
|
|
160
194
|
|
|
@@ -164,9 +198,11 @@ Collections and lists of objects, including embedded `object[]` fields, return:
|
|
|
164
198
|
{ "data": [], "total": 0 }
|
|
165
199
|
```
|
|
166
200
|
|
|
167
|
-
Primitive arrays
|
|
201
|
+
Primitive arrays are returned as plain arrays. Every object list accepts optional `where`, `order` and `pager`. Processing order is filter → sort → pagination. `total` is the filtered record count before pagination.
|
|
202
|
+
|
|
203
|
+
Use `page` and `pageSize` in `pager`. The default is the first page with the size from `server.pageSize`. Both values must be positive integers; `pageSize` is limited by `server.maxPageSize`. Out-of-range pages return empty `data` with the total matching record count in `total`.
|
|
168
204
|
|
|
169
|
-
`where` uses field operators `eq`, `ne`, `in`, string `contains`/`startsWith`/`endsWith`, and comparisons `gt`, `gte`, `lt`, `lte`.
|
|
205
|
+
`where` uses field operators `eq`, `ne`, `in`, string `contains`/`startsWith`/`endsWith`, and comparisons `gt`, `gte`, `lt`, `lte`. Combine conditions with `and`, `or`, `not`. Arrays support `some`, `every`, `none`; primitive arrays also support `contains`, `in`. String matching is case-insensitive. A field condition is an object containing an operator, such as `{ "id": { "eq": "1" } }`.
|
|
170
206
|
|
|
171
207
|
```json
|
|
172
208
|
{
|
|
@@ -182,9 +218,9 @@ Primitive arrays remain plain arrays. Every object list accepts optional `where`
|
|
|
182
218
|
}
|
|
183
219
|
```
|
|
184
220
|
|
|
185
|
-
Root
|
|
221
|
+
Root `where` selects records from the main collection. `where` inside a relation filters its elements while retaining the parent record. Each nested list is processed independently. Filtering by a relation works independently of its inclusion in the response.
|
|
186
222
|
|
|
187
|
-
`order` is an array of `{ "field": "fullName", "direction": "ASC" }` rules. Earlier rules have priority;
|
|
223
|
+
`order` is an array of `{ "field": "fullName", "direction": "ASC" }` rules. Earlier rules have priority; equal values retain storage order. Null and missing values compare equally. REST uses dotted field paths; GraphQL uses generated enums (`profile_name` for `profile.name`). Ambiguous enum names cause a generation error. Sorting supports scalar fields of the current object, including nested fields. Related lists accept their own `order`.
|
|
188
224
|
|
|
189
225
|
### REST
|
|
190
226
|
|
|
@@ -197,7 +233,7 @@ Root filters choose parents. Filters inside a selected relation only trim that r
|
|
|
197
233
|
| PATCH | `/users/{id}` | `userUpdate` |
|
|
198
234
|
| DELETE | `/users/{id}` | `userDelete` |
|
|
199
235
|
|
|
200
|
-
The path
|
|
236
|
+
The path parameter name follows the primary key. POST, PUT and PATCH accept a JSON record object. PUT replaces the record while retaining its key and server-managed fields. PATCH merges fields at the top level; supplied nested objects are replaced while preserving their read-only fields. Creation and replacement require all mandatory fields. Updates validate supplied values and the final record. Missing records return `404`; conflicts return `409`. DELETE returns the deleted record.
|
|
201
237
|
|
|
202
238
|
Query parameters `where`, `order`, `pager`, `nested` contain JSON. `scope` is a selection string. Example shown before URL encoding:
|
|
203
239
|
|
|
@@ -215,7 +251,7 @@ const params = new URLSearchParams({
|
|
|
215
251
|
const response = await fetch(`/users?${params}`);
|
|
216
252
|
```
|
|
217
253
|
|
|
218
|
-
`scope=*,actors(user(id,fullName),genres(*))` selects own fields and
|
|
254
|
+
`scope=*,actors(user(id,fullName),genres(*))` selects own fields and the specified relations. `*` includes the current object's own fields and stored keys, except `writeOnly` fields. Relations are listed explicitly. The default selection is own fields. Lists retain the `{ data, total }` response structure.
|
|
219
255
|
|
|
220
256
|
`nested` maps full response paths to list options:
|
|
221
257
|
|
|
@@ -229,7 +265,7 @@ const response = await fetch(`/users?${params}`);
|
|
|
229
265
|
}
|
|
230
266
|
```
|
|
231
267
|
|
|
232
|
-
A nested
|
|
268
|
+
A path in `nested` must be selected by `scope` and point to an object list. Single-record routes and mutations accept `scope` and `nested`; root `where`, `order` and `pager` apply to collection GET. Invalid names and unsafe paths return `400`.
|
|
233
269
|
|
|
234
270
|
### GraphQL
|
|
235
271
|
|
|
@@ -252,10 +288,9 @@ query {
|
|
|
252
288
|
}
|
|
253
289
|
```
|
|
254
290
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
String primary keys use GraphQL `ID`; ordinary strings use `String`, numbers use `Float`, pagination uses `Int`. Schema enums preserve valid string labels; other values receive `VALUE_0`, `VALUE_1`, etc. Schema constraints such as string length and formats are enforced by the shared runtime validator; SDL alone cannot express all constraints. Introspection and ordinary query/mutation execution are supported; this release does not add subscriptions or bulk mutations.
|
|
291
|
+
The query `user(id: ...)` returns one record or `null` if it is missing. Mutations are `userCreate(data: ...)`, `userReplace(id: ..., data: ...)`, `userUpdate(id: ..., data: ...)`, `userDelete(id: ...)`. For models containing only generated fields, the create mutation takes no `data` argument. Writes and validation follow the same rules as REST. Relations selected in a mutation result determine the response contents.
|
|
258
292
|
|
|
293
|
+
String primary keys use GraphQL `ID`; ordinary strings use `String`, numbers use `Float`, and pagination parameters use `Int`. Schema enums preserve valid string labels; other values receive `VALUE_0`, `VALUE_1`, etc. String lengths, formats and other model constraints are validated by the server during request execution. Introspection is available for exploring the schema. Selected list arguments are validated before executing mutations. Errors include `extensions.code`: `INVALID_INPUT`, `INVALID_QUERY`, `NOT_FOUND`, `CONFLICT` or `INTERNAL_ERROR`.
|
|
259
294
|
|
|
260
295
|
## Example database
|
|
261
296
|
|
|
@@ -363,10 +398,10 @@ String primary keys use GraphQL `ID`; ordinary strings use `String`, numbers use
|
|
|
363
398
|
|
|
364
399
|
## Files
|
|
365
400
|
|
|
366
|
-
Add `files.directory` and `files.metadata` to the
|
|
401
|
+
Add `files.directory` and `files.metadata` to the configuration and start the server:
|
|
367
402
|
|
|
368
403
|
```bash
|
|
369
|
-
deep-json-server
|
|
404
|
+
deep-json-server server.config.js
|
|
370
405
|
```
|
|
371
406
|
|
|
372
407
|
For temporary tests, use `files.data` instead. Each initial record contains `name`, `mimeType`, binary `content` as a `Uint8Array`, and an optional `directory`. Uploaded files then remain in memory until the process exits.
|
|
@@ -422,37 +457,53 @@ Content-Type: application/json
|
|
|
422
457
|
|
|
423
458
|
`PATCH` returns the updated metadata with status `200`; if a file already exists at the new path, the server returns `409`. `DELETE` returns `204` without a response body. A missing file returns `404` on every path-based operation. File paths in URLs are relative to `files.directory`, and all returned URLs are relative to the server origin.
|
|
424
459
|
|
|
425
|
-
In disk mode, the binary is stored at `<files.directory>/<directory>/<name>`.
|
|
460
|
+
In disk mode, the binary is stored at `<files.directory>/<directory>/<name>`. Metadata stores `directory`, `mimeType` and `name`; the server reads the size from the file and builds its URLs. Directories and the metadata file are created when needed.
|
|
461
|
+
|
|
462
|
+
Use one server process per disk database and file store. Stop it before editing stored files or metadata manually. Storage paths cannot contain symbolic links. Uploads and renames cannot overwrite the database, counters, schema, loaded configuration or metadata file.
|
|
426
463
|
|
|
427
|
-
|
|
464
|
+
Send the file as a binary request body. In a browser, use `xhr.send(file)` and track progress through `XMLHttpRequest.upload.onprogress`. The default maximum size is 100 MiB and can be changed through `server.maxFileSize`. Missing or unsafe headers and paths return `400`, an exceeded limit returns `413`, and a missing, malformed, or Fastify-unsupported `Content-Type` returns `400` or `415`, depending on which validation stage rejects it.
|
|
428
465
|
|
|
429
466
|
## Programmatic API
|
|
430
467
|
|
|
431
468
|
```js
|
|
432
|
-
import { createServer } from '@kollors/deep-json-server';
|
|
469
|
+
import { createServer } from '@kollors/deep-json-server/server';
|
|
433
470
|
import config from './server.config.js';
|
|
434
471
|
|
|
435
472
|
const facade = await createServer(config);
|
|
436
|
-
const openapi = await facade.openapi();
|
|
437
|
-
const sdl = await facade.graphql();
|
|
438
473
|
const server = facade.fastify();
|
|
439
474
|
await server.listen();
|
|
440
475
|
// await server.close();
|
|
441
476
|
```
|
|
442
477
|
|
|
443
|
-
|
|
478
|
+
The `openapi()` and `graphql()` methods return schemas and require `database.schema`. `fastify()` returns the server instance for configuration and startup. The database and enabled services initialize on `ready()`, `listen()` or the first `inject()`; initialization errors stop startup. Override server features with `createServer(config, { files: false, graphql: true, openapi: true })`.
|
|
479
|
+
|
|
480
|
+
The root import `@kollors/deep-json-server` also provides these functions. Server adapters load when enabled. Generators can be used independently:
|
|
481
|
+
|
|
482
|
+
```js
|
|
483
|
+
import { generateOpenapi, writeOpenapi } from '@kollors/deep-json-server/openapi';
|
|
484
|
+
import { generateGraphql, writeGraphql } from '@kollors/deep-json-server/graphql';
|
|
485
|
+
|
|
486
|
+
const document = await generateOpenapi('./schema.json', { files: true });
|
|
487
|
+
const sdl = await generateGraphql('./schema.json');
|
|
488
|
+
await writeOpenapi(document, './generated/openapi.yaml');
|
|
489
|
+
await writeGraphql(sdl, './generated/schema.graphql');
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
`generateOpenapi()` also accepts `host`, `port`, `pageSize`, `maxPageSize` and `info`. Pass a schema object instead of a path if preferred. Servers and generators use their own copy of the model. Pagination sizes must be positive integers; `pageSize` cannot exceed `maxPageSize`.
|
|
444
493
|
|
|
445
494
|
## Storage and development
|
|
446
495
|
|
|
447
|
-
Updates
|
|
496
|
+
Updates run sequentially within one server instance and are validated on a copy of the data before saving. Use one server process per database file. `increment` counters are stored next to the database in `<database path>.counters.json`; keep that file with the database. Numbers are reserved before the data write, so a failed write can leave gaps but cannot reuse a reserved number.
|
|
448
497
|
|
|
449
|
-
|
|
498
|
+
The server is intended for mocking APIs. Implement authentication and password hashing in your application if needed.
|
|
450
499
|
|
|
451
500
|
```sh
|
|
452
501
|
npm ci
|
|
453
502
|
npm run verify
|
|
454
503
|
```
|
|
455
504
|
|
|
456
|
-
|
|
505
|
+
The command checks types, code style, test coverage and installation from the package archive.
|
|
506
|
+
|
|
507
|
+
To publish a new alpha, update the version in `package.json`, `package-lock.json` and `src/constants.ts`, then push to `main`. GitHub Actions creates the version tag and publishes to npm `alpha` through trusted publishing. Already published versions are skipped. If the tag exists but publication failed, a retry uses that tag and verifies that the package files match it. Pushing a version tag also triggers publication; stable versions publish to `latest`.
|
|
457
508
|
|
|
458
509
|
License: MIT.
|