@kollors/deep-json-server 1.0.0-beta.5 → 1.0.0-rc.1
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/CHANGELOG.md +14 -0
- package/MIGRATION.md +41 -0
- package/README.md +36 -30
- package/README.ru.md +49 -43
- package/dist/index.d.ts +1 -1
- package/dist/src/cli/index.js +15 -10
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/core/config-values.js +4 -4
- package/dist/src/core/config-values.js.map +1 -1
- package/dist/src/core/constants.d.ts +1 -1
- package/dist/src/core/constants.js +1 -1
- package/dist/src/core/constants.js.map +1 -1
- package/dist/src/core/database.js +16 -16
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/project-package.d.ts +9 -0
- package/dist/src/core/project-package.js +27 -0
- package/dist/src/core/project-package.js.map +1 -0
- package/dist/src/core/utils.js +2 -2
- package/dist/src/core/utils.js.map +1 -1
- package/dist/src/files/contract.js +8 -8
- package/dist/src/files/contract.js.map +1 -1
- package/dist/src/files/disk-metadata.js +3 -3
- package/dist/src/files/disk-metadata.js.map +1 -1
- package/dist/src/files/disk-paths.js +6 -6
- package/dist/src/files/disk-paths.js.map +1 -1
- package/dist/src/files/disk-store.js +10 -10
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/files/memory-store.js +8 -8
- package/dist/src/files/memory-store.js.map +1 -1
- package/dist/src/files/routes.js +9 -9
- package/dist/src/files/routes.js.map +1 -1
- package/dist/src/files/streams.js +1 -1
- package/dist/src/files/streams.js.map +1 -1
- package/dist/src/openapi/entry.d.ts +1 -1
- package/dist/src/openapi/entry.js.map +1 -1
- package/dist/src/openapi/generate.d.ts +3 -3
- package/dist/src/openapi/generate.js +7 -5
- package/dist/src/openapi/generate.js.map +1 -1
- package/dist/src/openapi/options.d.ts +7 -1
- package/dist/src/openapi/options.js +6 -0
- package/dist/src/openapi/options.js.map +1 -1
- package/dist/src/server/bootstrap.js +1 -1
- package/dist/src/server/bootstrap.js.map +1 -1
- package/dist/src/server/config.d.ts +19 -5
- package/dist/src/server/config.js +11 -6
- package/dist/src/server/config.js.map +1 -1
- package/dist/src/server/create.d.ts +2 -1
- package/dist/src/server/create.js +8 -4
- package/dist/src/server/create.js.map +1 -1
- package/dist/src/server/http.js +1 -1
- package/dist/src/server/http.js.map +1 -1
- package/dist/src/server/input-paths.d.ts +1 -0
- package/dist/src/server/input-paths.js +9 -1
- package/dist/src/server/input-paths.js.map +1 -1
- package/dist/src/server/openapi-options.d.ts +2 -2
- package/dist/src/server/openapi-options.js +2 -2
- package/dist/src/server/openapi-options.js.map +1 -1
- package/dist/src/server/public.d.ts +1 -1
- package/examples/database.json +99 -0
- package/examples/schema.json +153 -0
- package/examples/server.config.js +8 -0
- package/package.json +5 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0-rc.1
|
|
4
|
+
|
|
5
|
+
First release candidate for the 1.0 API. This release includes schema-driven REST, GraphQL, OpenAPI export, authentication, record ownership, timestamps, soft deletion, and file storage. It also makes CLI and API error messages consistently English and checks TypeScript declarations from an installed package archive.
|
|
6
|
+
|
|
7
|
+
The 1.0 configuration, CLI flags, and REST query format differ from 0.9.0. Follow the [migration guide](MIGRATION.md) before upgrading an existing project. In particular, the REST `scope` wildcard includes scalar fields only; select arrays, objects, relations, and relation keys explicitly.
|
|
8
|
+
|
|
9
|
+
### Verification
|
|
10
|
+
|
|
11
|
+
- TypeScript source and contract checks, lint, and coverage-gated tests.
|
|
12
|
+
- Package installation smoke test for the CLI, REST, GraphQL, OpenAPI, and auth.
|
|
13
|
+
- TypeScript consumer test against the installed package declarations.
|
|
14
|
+
- CI matrix for Node.js 22, 24, and 26 on Linux.
|
package/MIGRATION.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Migrating from 0.9.0 to 1.0.0-rc.1
|
|
2
|
+
|
|
3
|
+
Version 1.0 changes configuration and request syntax. Update the server configuration and client requests together. Back up any file database, auth records, and file metadata before changing the running server.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
Declare a storage mode and use `source` for each enabled component:
|
|
8
|
+
|
|
9
|
+
| 0.9.0 | 1.0.0-rc.1 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `database.path` | `storage: 'file'`, `database.source` |
|
|
12
|
+
| `database.data` | `storage: 'memory'`, `database.source` |
|
|
13
|
+
| `files.directory` | `files.source` in file mode |
|
|
14
|
+
| `files.data` | `files.source` in memory mode |
|
|
15
|
+
| `openapi.path` | `openapi.target` |
|
|
16
|
+
|
|
17
|
+
The `storage` mode applies to the database, schema, auth records, files, and package metadata. GraphQL and OpenAPI require a model schema and `package.source`. The schema format has changed: define models under `models`, with a `collection`, fields, and one primary key per model. Start with the [current schema example](examples/schema.json), then validate your existing records against it. The [configuration example](examples/server.config.js) shows all required paths.
|
|
18
|
+
|
|
19
|
+
## CLI
|
|
20
|
+
|
|
21
|
+
Adding a `files`, `graphql`, or `openapi` section enables that feature. The old `--files`, `--openapi`, and `--openapi-only` flags are gone. Use `--generate` to export configured schemas and start the server, or `--generate-only` to export and exit. Each exported format needs a `target` path.
|
|
22
|
+
|
|
23
|
+
## REST queries
|
|
24
|
+
|
|
25
|
+
REST now accepts a JSON `scope` query parameter. Replace `_where`, `_sort`, `_page`, `_perPage`, `_embed`, and simple field filters with `scope`. For example:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
const scope = [
|
|
29
|
+
{ id: true, title: true, publishers: [{ id: true, name: true }] },
|
|
30
|
+
{ where: { title: { contains: 'Ardenia' } }, order: [{ field: 'title', direction: 'ASC' }], pager: { page: 1, pageSize: 10 } },
|
|
31
|
+
];
|
|
32
|
+
const url = `/movies?${new URLSearchParams({ scope: JSON.stringify(scope) })}`;
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Without an explicit `scope`, the response contains scalar fields only. `"*": true` also selects only scalar fields that do not store relation keys. Select arrays, objects, relations, and relation keys explicitly. Related lists can have their own filters, order, and pagination. Review clients that expect embedded relations or relation keys in default responses.
|
|
36
|
+
|
|
37
|
+
## Records and auth
|
|
38
|
+
|
|
39
|
+
Explicit models validate fields and relations more strictly than the 0.9 schemaless server. Existing records with undeclared fields or dangling direct relation keys may fail validation at startup or on write. Test the migrated database before replacing the production file.
|
|
40
|
+
|
|
41
|
+
Authentication is optional and enabled by an `auth` section. When enabled, creating records requires login; changing existing records requires ownership or administrator access. Record timestamps and soft deletion are configured in the model schema. The [README](README.md) describes the current behavior and API endpoints.
|
package/README.md
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
[Русский](README.ru.md)
|
|
4
4
|
|
|
5
|
+
[Release notes](CHANGELOG.md) · [Migration from 0.9.0](MIGRATION.md)
|
|
6
|
+
|
|
5
7
|
A JSON mock server with REST, GraphQL, related records, file uploads and schema exports. Supports user login, owner and administrator permissions, record timestamps and soft deletion. Requires Node.js 22 or newer.
|
|
6
8
|
|
|
7
|
-
**Breaking changes
|
|
9
|
+
**Breaking changes in 1.0.0.** See the [migration guide](MIGRATION.md) when upgrading from 0.9.0. The REST `scope` wildcard selects only scalar fields that do not store relation keys. Arrays, objects, relations and their keys must be selected explicitly. With auth enabled, record permissions are available through the virtual `actions` field.
|
|
8
10
|
|
|
9
11
|
## Installation
|
|
10
12
|
|
|
11
13
|
```sh
|
|
12
|
-
npm install @kollors/deep-json-server@
|
|
14
|
+
npm install @kollors/deep-json-server@rc
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
To install
|
|
17
|
+
To install this release candidate, use `@1.0.0-rc.1`.
|
|
16
18
|
|
|
17
19
|
## Quick start
|
|
18
20
|
|
|
@@ -23,7 +25,7 @@ Create two files in the same directory.
|
|
|
23
25
|
```json
|
|
24
26
|
{
|
|
25
27
|
"users": [
|
|
26
|
-
{ "id": "1", "fullName": "
|
|
28
|
+
{ "id": "1", "fullName": "Mira Volkova" }
|
|
27
29
|
]
|
|
28
30
|
}
|
|
29
31
|
```
|
|
@@ -44,7 +46,7 @@ Add a [model schema](#model-schema) to define relations and validation. See [que
|
|
|
44
46
|
|
|
45
47
|
## Configuration
|
|
46
48
|
|
|
47
|
-
With `storage: 'file'`,
|
|
49
|
+
With `storage: 'file'`, provide paths for every source and the schema. With `'memory'`, provide data directly. Use the same mode throughout the configuration. Add `auth`, `files`, `graphql` or `openapi` to enable those features. `graphql: {}` and `openapi: {}` expose HTTP endpoints at their default paths; add `target` to export a schema.
|
|
48
50
|
|
|
49
51
|
```js
|
|
50
52
|
export default {
|
|
@@ -54,6 +56,7 @@ export default {
|
|
|
54
56
|
files: { source: './uploads' },
|
|
55
57
|
graphql: { target: './generated/schema.graphql' },
|
|
56
58
|
openapi: { target: './generated/openapi.yaml' },
|
|
59
|
+
package: { source: './package.json' },
|
|
57
60
|
server: { host: '127.0.0.1', port: 4001 },
|
|
58
61
|
};
|
|
59
62
|
```
|
|
@@ -71,13 +74,15 @@ export default {
|
|
|
71
74
|
| `graphql.target` | GraphQL SDL export destination |
|
|
72
75
|
| `openapi.endpoint` | HTTP endpoint; default `/openapi.json` |
|
|
73
76
|
| `openapi.target` | OpenAPI export destination |
|
|
74
|
-
| `
|
|
77
|
+
| `package.source` | Project `package.json`; required when `openapi` or `graphql` is configured |
|
|
75
78
|
| `server.host`, `server.port` | Defaults `127.0.0.1`, `4001`; CLI also reads `HOST`/`PORT` |
|
|
76
79
|
| `server.pageSize`, `server.maxPageSize` | Defaults 10 and 100; default size is capped by the maximum |
|
|
77
80
|
| `server.cors`, `server.logger` | Default `true`; logger also accepts Fastify logger options |
|
|
78
81
|
| `server.maxFileSize` | Default 100 MiB |
|
|
79
82
|
|
|
80
|
-
|
|
83
|
+
`package.source` follows the storage mode. With `storage: 'file'`, pass a path to `package.json`. With `storage: 'memory'`, pass its metadata directly: `{ name: 'example-api', version: '1.0.0', description: 'Example API' }`; `name` and `version` are required, while `description` is optional.
|
|
84
|
+
|
|
85
|
+
Relative paths resolve from the configuration file directory, or from the working directory with `createServer(config)`. In-memory data, including the schema and package metadata, is copied. Port `0` lets the system choose an available port.
|
|
81
86
|
|
|
82
87
|
### CLI
|
|
83
88
|
|
|
@@ -222,37 +227,37 @@ Cascading deletion runs as one operation, including cyclic relations. A validati
|
|
|
222
227
|
{
|
|
223
228
|
"id": "1",
|
|
224
229
|
"isArchived": false,
|
|
225
|
-
"name": "
|
|
230
|
+
"name": "Ardenia"
|
|
226
231
|
},
|
|
227
232
|
{
|
|
228
233
|
"id": "2",
|
|
229
234
|
"isArchived": false,
|
|
230
|
-
"name": "
|
|
235
|
+
"name": "Veloria"
|
|
231
236
|
}
|
|
232
237
|
],
|
|
233
238
|
"genres": [
|
|
234
239
|
{
|
|
235
240
|
"id": "1",
|
|
236
241
|
"isArchived": false,
|
|
237
|
-
"name": "
|
|
242
|
+
"name": "Crime",
|
|
238
243
|
"parentIds": []
|
|
239
244
|
},
|
|
240
245
|
{
|
|
241
246
|
"id": "2",
|
|
242
247
|
"isArchived": false,
|
|
243
|
-
"name": "
|
|
248
|
+
"name": "Gangster",
|
|
244
249
|
"parentIds": ["1"]
|
|
245
250
|
},
|
|
246
251
|
{
|
|
247
252
|
"id": "3",
|
|
248
253
|
"isArchived": false,
|
|
249
|
-
"name": "
|
|
254
|
+
"name": "Drama",
|
|
250
255
|
"parentIds": []
|
|
251
256
|
},
|
|
252
257
|
{
|
|
253
258
|
"id": "4",
|
|
254
259
|
"isArchived": false,
|
|
255
|
-
"name": "
|
|
260
|
+
"name": "Comedy",
|
|
256
261
|
"parentIds": []
|
|
257
262
|
}
|
|
258
263
|
],
|
|
@@ -271,20 +276,20 @@ Cascading deletion runs as one operation, including cyclic relations. A validati
|
|
|
271
276
|
}
|
|
272
277
|
],
|
|
273
278
|
"coverSrc": "https://example.com/covers/shadows-of-ardenia.jpg",
|
|
274
|
-
"description": "
|
|
279
|
+
"description": "An heiress in a port city uncovers a plot involving two rival families.",
|
|
275
280
|
"id": "1",
|
|
276
281
|
"isArchived": false,
|
|
277
282
|
"publisherIds": ["2"],
|
|
278
|
-
"title": "
|
|
283
|
+
"title": "Shadows of Ardenia"
|
|
279
284
|
},
|
|
280
285
|
{
|
|
281
286
|
"actors": [],
|
|
282
287
|
"coverSrc": "https://example.com/covers/northern-star.jpg",
|
|
283
|
-
"description": "
|
|
288
|
+
"description": "A night clerk at an old hotel gets drawn into the search for a missing painting.",
|
|
284
289
|
"id": "2",
|
|
285
290
|
"isArchived": false,
|
|
286
291
|
"publisherIds": ["1"],
|
|
287
|
-
"title": "
|
|
292
|
+
"title": "Midnight at the Northern Star"
|
|
288
293
|
}
|
|
289
294
|
],
|
|
290
295
|
"publishers": [
|
|
@@ -303,14 +308,14 @@ Cascading deletion runs as one operation, including cyclic relations. A validati
|
|
|
303
308
|
{
|
|
304
309
|
"bornAt": "1988-03-14",
|
|
305
310
|
"countryId": "1",
|
|
306
|
-
"fullName": "
|
|
311
|
+
"fullName": "Mira Volkova",
|
|
307
312
|
"id": "1",
|
|
308
313
|
"isArchived": false
|
|
309
314
|
},
|
|
310
315
|
{
|
|
311
316
|
"bornAt": "1991-11-02",
|
|
312
317
|
"countryId": "2",
|
|
313
|
-
"fullName": "
|
|
318
|
+
"fullName": "Leon Vetrov",
|
|
314
319
|
"id": "2",
|
|
315
320
|
"isArchived": false
|
|
316
321
|
}
|
|
@@ -390,7 +395,7 @@ const scope = [
|
|
|
390
395
|
],
|
|
391
396
|
},
|
|
392
397
|
{
|
|
393
|
-
where: { fullName: { contains: '
|
|
398
|
+
where: { fullName: { contains: 'Mira' } },
|
|
394
399
|
order: [{ field: 'fullName', direction: 'ASC' }],
|
|
395
400
|
pager: { page: 1, pageSize: 20 },
|
|
396
401
|
},
|
|
@@ -465,7 +470,7 @@ Use either the relation field or its storage key in an object, for example `genr
|
|
|
465
470
|
}
|
|
466
471
|
```
|
|
467
472
|
|
|
468
|
-
The server
|
|
473
|
+
The server rejects both fields together and rolls back the operation. Relation fields accept objects only; use `genreIds` to change links without creating or updating related records. Reverse relations update the target key. If a target path crosses an array and the server cannot identify one element to attach, provide the array with the intended keys explicitly. Protected keys cannot be changed.
|
|
469
474
|
|
|
470
475
|
All nested changes belong to the main record's transaction. A validation error, missing record or invalid response selection rolls back the entire operation. Updating a shared record affects every record linked to it.
|
|
471
476
|
|
|
@@ -486,7 +491,7 @@ mutation {
|
|
|
486
491
|
|
|
487
492
|
### GraphQL
|
|
488
493
|
|
|
489
|
-
Set `database.schema` and add `graphql: {}` to the configuration:
|
|
494
|
+
Set `database.schema` and add `graphql: {}` plus `package.source` to the configuration:
|
|
490
495
|
|
|
491
496
|
```sh
|
|
492
497
|
npx deep-json-server server.config.js
|
|
@@ -497,7 +502,7 @@ Send requests to `/graphql` using POST with `Content-Type: application/json` and
|
|
|
497
502
|
```graphql
|
|
498
503
|
query {
|
|
499
504
|
userList(
|
|
500
|
-
where: { fullName: { contains: "
|
|
505
|
+
where: { fullName: { contains: "Mira" } }
|
|
501
506
|
order: [{ field: fullName, direction: ASC }]
|
|
502
507
|
pager: { page: 1, pageSize: 20 }
|
|
503
508
|
) {
|
|
@@ -506,7 +511,7 @@ query {
|
|
|
506
511
|
id
|
|
507
512
|
fullName
|
|
508
513
|
movies(
|
|
509
|
-
where: { title: { contains: "
|
|
514
|
+
where: { title: { contains: "Shadows" } }
|
|
510
515
|
order: [{ field: title, direction: ASC }]
|
|
511
516
|
pager: { pageSize: 5 }
|
|
512
517
|
) {
|
|
@@ -526,7 +531,7 @@ Errors include `extensions.code`: `INVALID_INPUT`, `INVALID_QUERY`, `NOT_FOUND`,
|
|
|
526
531
|
|
|
527
532
|
## OpenAPI and schema exports
|
|
528
533
|
|
|
529
|
-
Exports use OpenAPI 3.0.3. Add `openapi: {}` and `
|
|
534
|
+
Exports use OpenAPI 3.0.3. Add `openapi: {}`, `database.schema` and `package.source` to serve the specification at `/openapi.json`. Change the route with `openapi.endpoint`. OpenAPI `info.title`, `info.version` and optional `info.description` come from the configured `package.json`. Open the document in Swagger UI or import it into an API client.
|
|
530
535
|
|
|
531
536
|
Set output paths to save schemas:
|
|
532
537
|
|
|
@@ -536,6 +541,7 @@ export default {
|
|
|
536
541
|
database: { source: './database.json', schema: './schema.json' },
|
|
537
542
|
openapi: { target: './generated/openapi.yaml' },
|
|
538
543
|
graphql: { target: './generated/schema.graphql' },
|
|
544
|
+
package: { source: './package.json' },
|
|
539
545
|
};
|
|
540
546
|
```
|
|
541
547
|
|
|
@@ -808,7 +814,7 @@ await server.listen();
|
|
|
808
814
|
|
|
809
815
|
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.
|
|
810
816
|
|
|
811
|
-
`createServer(config)` takes
|
|
817
|
+
`createServer(config)` takes the same configuration object as the CLI. When `openapi` or `graphql` is configured, `package.source` is required. The `openapi()` and `graphql()` methods require their respective sections. They return schemas without writing files.
|
|
812
818
|
|
|
813
819
|
The root import `@kollors/deep-json-server` also provides these functions. Server adapters load when enabled. Generators can be used independently:
|
|
814
820
|
|
|
@@ -816,7 +822,7 @@ The root import `@kollors/deep-json-server` also provides these functions. Serve
|
|
|
816
822
|
import { generateOpenapi, writeOpenapi } from '@kollors/deep-json-server/openapi';
|
|
817
823
|
import { generateGraphql, writeGraphql } from '@kollors/deep-json-server/graphql';
|
|
818
824
|
|
|
819
|
-
const document = await generateOpenapi('./schema.json', { files: true });
|
|
825
|
+
const document = await generateOpenapi('./schema.json', { files: true, packagePath: './package.json' });
|
|
820
826
|
const sdl = await generateGraphql('./schema.json');
|
|
821
827
|
await writeOpenapi(document, './generated/openapi.yaml');
|
|
822
828
|
await writeGraphql(sdl, './generated/schema.graphql');
|
|
@@ -824,7 +830,7 @@ await writeGraphql(sdl, './generated/schema.graphql');
|
|
|
824
830
|
|
|
825
831
|
Standalone generators accept a schema path or object without a server configuration. The selected function supplies the default format; a model's `api` setting can restrict it. Timestamps and soft deletion come from the schema. `{ auth: true }` adds ownership and `actions` fields; OpenAPI also describes auth routes and token requirements. `hashPassword()` is available from the root package.
|
|
826
832
|
|
|
827
|
-
`generateOpenapi()` also accepts `host`, `port`, `pageSize
|
|
833
|
+
`generateOpenapi()` requires `packagePath` and also accepts `host`, `port`, `pageSize` and `maxPageSize`. It reads OpenAPI metadata from that package. 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`.
|
|
828
834
|
|
|
829
835
|
## Data storage
|
|
830
836
|
|
|
@@ -832,14 +838,14 @@ Updates run sequentially within one server instance and are validated on a copy
|
|
|
832
838
|
|
|
833
839
|
## Development
|
|
834
840
|
|
|
835
|
-
|
|
841
|
+
The source code is organized into `rest`, `graphql`, `openapi`, `auth`, `files`, `cli` and `server`. Shared models, storage, queries and mutation rules live in `core`. The `server` module connects them; API generators load independently of the HTTP runtime.
|
|
836
842
|
|
|
837
843
|
```sh
|
|
838
844
|
npm ci
|
|
839
845
|
npm run verify
|
|
840
846
|
```
|
|
841
847
|
|
|
842
|
-
|
|
848
|
+
`npm run verify` checks types, code style, test coverage and installation from the package archive.
|
|
843
849
|
|
|
844
850
|
To publish a prerelease, update the version in `package.json`, `package-lock.json` and `src/core/constants.ts`, then push the commit to `main`. GitHub Actions creates its `v<version>` tag and publishes through trusted publishing to the `alpha`, `beta` or `rc` channel. Stable versions publish to `latest` from an explicitly pushed version tag.
|
|
845
851
|
|
package/README.ru.md
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[История выпусков](CHANGELOG.md) · [Переход с 0.9.0](MIGRATION.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
JSON-сервер для создания тестового API с REST, GraphQL, связями между записями, загрузкой файлов и экспортом схем. Поддерживает вход пользователей, права владельца и администратора, даты записей и мягкое удаление. Требуется Node.js 22 или новее.
|
|
8
|
+
|
|
9
|
+
**Изменения в 1.0.0, нарушающие совместимость.** При переходе с 0.9.0 воспользуйтесь [инструкцией по миграции](MIGRATION.md). `*` в REST `scope` выбирает только скалярные поля, которые не хранят ключи связей. Массивы, объекты, связи и их ключи нужно указывать явно. При включённой аутентификации права на запись доступны через виртуальное поле `actions`.
|
|
8
10
|
|
|
9
11
|
## Установка
|
|
10
12
|
|
|
11
13
|
```sh
|
|
12
|
-
npm install @kollors/deep-json-server@
|
|
14
|
+
npm install @kollors/deep-json-server@rc
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
Для установки
|
|
17
|
+
Для установки этого релиз-кандидата укажите `@1.0.0-rc.1`.
|
|
16
18
|
|
|
17
19
|
## Быстрый старт
|
|
18
20
|
|
|
@@ -23,7 +25,7 @@ npm install @kollors/deep-json-server@beta
|
|
|
23
25
|
```json
|
|
24
26
|
{
|
|
25
27
|
"users": [
|
|
26
|
-
{ "id": "1", "fullName": "
|
|
28
|
+
{ "id": "1", "fullName": "Mira Volkova" }
|
|
27
29
|
]
|
|
28
30
|
}
|
|
29
31
|
```
|
|
@@ -44,7 +46,7 @@ npx deep-json-server server.config.js
|
|
|
44
46
|
|
|
45
47
|
## Конфигурация
|
|
46
48
|
|
|
47
|
-
При `storage: 'file'`
|
|
49
|
+
При `storage: 'file'` задайте пути для всех источников и схемы, при `'memory'` — передайте данные напрямую. Используйте один режим во всей конфигурации. Секции `auth`, `files`, `graphql` и `openapi` включают соответствующие возможности. `graphql: {}` и `openapi: {}` открывают HTTP-маршруты по стандартным адресам; для экспорта схемы добавьте `target`.
|
|
48
50
|
|
|
49
51
|
```js
|
|
50
52
|
export default {
|
|
@@ -54,6 +56,7 @@ export default {
|
|
|
54
56
|
files: { source: './uploads' },
|
|
55
57
|
graphql: { target: './generated/schema.graphql' },
|
|
56
58
|
openapi: { target: './generated/openapi.yaml' },
|
|
59
|
+
package: { source: './package.json' },
|
|
57
60
|
server: { host: '127.0.0.1', port: 4001 },
|
|
58
61
|
};
|
|
59
62
|
```
|
|
@@ -71,13 +74,15 @@ export default {
|
|
|
71
74
|
| `graphql.target` | Файл для экспорта GraphQL SDL |
|
|
72
75
|
| `openapi.endpoint` | HTTP-маршрут; по умолчанию `/openapi.json` |
|
|
73
76
|
| `openapi.target` | Файл для экспорта OpenAPI |
|
|
74
|
-
| `
|
|
77
|
+
| `package.source` | `package.json` проекта; обязателен при наличии `openapi` или `graphql` |
|
|
75
78
|
| `server.host`, `server.port` | По умолчанию `127.0.0.1`, `4001`; CLI также читает `HOST`/`PORT` |
|
|
76
79
|
| `server.pageSize`, `server.maxPageSize` | По умолчанию 10 и 100; размер по умолчанию ограничен максимумом |
|
|
77
80
|
| `server.cors`, `server.logger` | По умолчанию `true`; logger принимает также настройки Fastify |
|
|
78
81
|
| `server.maxFileSize` | По умолчанию 100 МиБ |
|
|
79
82
|
|
|
80
|
-
|
|
83
|
+
Формат `package.source` зависит от режима хранения. При `storage: 'file'` укажите путь к `package.json`. При `storage: 'memory'` передайте метаданные напрямую: `{ name: 'example-api', version: '1.0.0', description: 'Example API' }`; `name` и `version` обязательны, `description` необязателен.
|
|
84
|
+
|
|
85
|
+
Относительные пути разрешаются от каталога файла конфигурации; при вызове `createServer(config)` — от рабочего каталога. Данные в памяти, включая схему и метаданные пакета, копируются. Порт `0` позволяет системе выбрать свободный порт.
|
|
81
86
|
|
|
82
87
|
### CLI
|
|
83
88
|
|
|
@@ -222,37 +227,37 @@ REST без схемы создаёт ключ `id` и сохраняет про
|
|
|
222
227
|
{
|
|
223
228
|
"id": "1",
|
|
224
229
|
"isArchived": false,
|
|
225
|
-
"name": "
|
|
230
|
+
"name": "Ardenia"
|
|
226
231
|
},
|
|
227
232
|
{
|
|
228
233
|
"id": "2",
|
|
229
234
|
"isArchived": false,
|
|
230
|
-
"name": "
|
|
235
|
+
"name": "Veloria"
|
|
231
236
|
}
|
|
232
237
|
],
|
|
233
238
|
"genres": [
|
|
234
239
|
{
|
|
235
240
|
"id": "1",
|
|
236
241
|
"isArchived": false,
|
|
237
|
-
"name": "
|
|
242
|
+
"name": "Crime",
|
|
238
243
|
"parentIds": []
|
|
239
244
|
},
|
|
240
245
|
{
|
|
241
246
|
"id": "2",
|
|
242
247
|
"isArchived": false,
|
|
243
|
-
"name": "
|
|
248
|
+
"name": "Gangster",
|
|
244
249
|
"parentIds": ["1"]
|
|
245
250
|
},
|
|
246
251
|
{
|
|
247
252
|
"id": "3",
|
|
248
253
|
"isArchived": false,
|
|
249
|
-
"name": "
|
|
254
|
+
"name": "Drama",
|
|
250
255
|
"parentIds": []
|
|
251
256
|
},
|
|
252
257
|
{
|
|
253
258
|
"id": "4",
|
|
254
259
|
"isArchived": false,
|
|
255
|
-
"name": "
|
|
260
|
+
"name": "Comedy",
|
|
256
261
|
"parentIds": []
|
|
257
262
|
}
|
|
258
263
|
],
|
|
@@ -271,20 +276,20 @@ REST без схемы создаёт ключ `id` и сохраняет про
|
|
|
271
276
|
}
|
|
272
277
|
],
|
|
273
278
|
"coverSrc": "https://example.com/covers/shadows-of-ardenia.jpg",
|
|
274
|
-
"description": "
|
|
279
|
+
"description": "An heiress in a port city uncovers a plot involving two rival families.",
|
|
275
280
|
"id": "1",
|
|
276
281
|
"isArchived": false,
|
|
277
282
|
"publisherIds": ["2"],
|
|
278
|
-
"title": "
|
|
283
|
+
"title": "Shadows of Ardenia"
|
|
279
284
|
},
|
|
280
285
|
{
|
|
281
286
|
"actors": [],
|
|
282
287
|
"coverSrc": "https://example.com/covers/northern-star.jpg",
|
|
283
|
-
"description": "
|
|
288
|
+
"description": "A night clerk at an old hotel gets drawn into the search for a missing painting.",
|
|
284
289
|
"id": "2",
|
|
285
290
|
"isArchived": false,
|
|
286
291
|
"publisherIds": ["1"],
|
|
287
|
-
"title": "
|
|
292
|
+
"title": "Midnight at the Northern Star"
|
|
288
293
|
}
|
|
289
294
|
],
|
|
290
295
|
"publishers": [
|
|
@@ -303,14 +308,14 @@ REST без схемы создаёт ключ `id` и сохраняет про
|
|
|
303
308
|
{
|
|
304
309
|
"bornAt": "1988-03-14",
|
|
305
310
|
"countryId": "1",
|
|
306
|
-
"fullName": "
|
|
311
|
+
"fullName": "Mira Volkova",
|
|
307
312
|
"id": "1",
|
|
308
313
|
"isArchived": false
|
|
309
314
|
},
|
|
310
315
|
{
|
|
311
316
|
"bornAt": "1991-11-02",
|
|
312
317
|
"countryId": "2",
|
|
313
|
-
"fullName": "
|
|
318
|
+
"fullName": "Leon Vetrov",
|
|
314
319
|
"id": "2",
|
|
315
320
|
"isArchived": false
|
|
316
321
|
}
|
|
@@ -371,11 +376,11 @@ npx deep-json-server examples/server.config.js
|
|
|
371
376
|
|
|
372
377
|
Имя параметра пути соответствует первичному ключу. POST, PUT и PATCH принимают JSON-объект записи. PUT заменяет запись с сохранением ключа и серверных полей. PATCH объединяет поля на верхнем уровне; переданные вложенные объекты заменяются с сохранением их полей `readOnly`. Создание и замена требуют всех обязательных полей. При обновлении проверяются переданные значения и итоговая запись. Отсутствующая запись — `404`, конфликт — `409`.
|
|
373
378
|
|
|
374
|
-
POST возвращает созданную запись со статусом `201`; PUT, PATCH и DELETE — результат со статусом `200`. Ошибки REST имеют вид `{ "error": "
|
|
379
|
+
POST возвращает созданную запись со статусом `201`; PUT, PATCH и DELETE — результат со статусом `200`. Ошибки REST имеют вид `{ "error": "Error description" }`.
|
|
375
380
|
|
|
376
381
|
### Параметры REST-запросов
|
|
377
382
|
|
|
378
|
-
Для запросов к записям REST принимает один параметр URL `scope` с JSON-массивом `[
|
|
383
|
+
Для запросов к записям REST принимает один параметр URL `scope` с JSON-массивом `[fields, arguments?]`. Первый объект выбирает поля, второй задаёт `where`, `order` и `pager` для списка. Этот формат одинаков для корневого запроса, вложенных объектов и связей.
|
|
379
384
|
|
|
380
385
|
Пример выбора пользователей и их фильмов с отдельной сортировкой и пагинацией:
|
|
381
386
|
|
|
@@ -390,7 +395,7 @@ const scope = [
|
|
|
390
395
|
],
|
|
391
396
|
},
|
|
392
397
|
{
|
|
393
|
-
where: { fullName: { contains: '
|
|
398
|
+
where: { fullName: { contains: 'Mira' } },
|
|
394
399
|
order: [{ field: 'fullName', direction: 'ASC' }],
|
|
395
400
|
pager: { page: 1, pageSize: 20 },
|
|
396
401
|
},
|
|
@@ -438,8 +443,8 @@ Content-Type: application/json
|
|
|
438
443
|
"userId": "1",
|
|
439
444
|
"genres": [
|
|
440
445
|
{ "id": "1" },
|
|
441
|
-
{ "id": "2", "name": "
|
|
442
|
-
{ "name": "
|
|
446
|
+
{ "id": "2", "name": "Updated genre" },
|
|
447
|
+
{ "name": "New genre" }
|
|
443
448
|
]
|
|
444
449
|
}
|
|
445
450
|
]
|
|
@@ -476,7 +481,7 @@ mutation {
|
|
|
476
481
|
movieUpdate(id: "1", data: {
|
|
477
482
|
actors: [{
|
|
478
483
|
userId: "1"
|
|
479
|
-
genres: [{ id: "2", name: "
|
|
484
|
+
genres: [{ id: "2", name: "Updated genre" }, { name: "New genre" }]
|
|
480
485
|
}]
|
|
481
486
|
}) {
|
|
482
487
|
actors { data { genres { data { id name } } } }
|
|
@@ -486,7 +491,7 @@ mutation {
|
|
|
486
491
|
|
|
487
492
|
### GraphQL
|
|
488
493
|
|
|
489
|
-
Укажите `database.schema` и добавьте
|
|
494
|
+
Укажите `database.schema` и добавьте в конфигурацию `graphql: {}` вместе с `package.source`:
|
|
490
495
|
|
|
491
496
|
```sh
|
|
492
497
|
npx deep-json-server server.config.js
|
|
@@ -497,7 +502,7 @@ npx deep-json-server server.config.js
|
|
|
497
502
|
```graphql
|
|
498
503
|
query {
|
|
499
504
|
userList(
|
|
500
|
-
where: { fullName: { contains: "
|
|
505
|
+
where: { fullName: { contains: "Mira" } }
|
|
501
506
|
order: [{ field: fullName, direction: ASC }]
|
|
502
507
|
pager: { page: 1, pageSize: 20 }
|
|
503
508
|
) {
|
|
@@ -506,7 +511,7 @@ query {
|
|
|
506
511
|
id
|
|
507
512
|
fullName
|
|
508
513
|
movies(
|
|
509
|
-
where: { title: { contains: "
|
|
514
|
+
where: { title: { contains: "Shadows" } }
|
|
510
515
|
order: [{ field: title, direction: ASC }]
|
|
511
516
|
pager: { pageSize: 5 }
|
|
512
517
|
) {
|
|
@@ -526,7 +531,7 @@ query {
|
|
|
526
531
|
|
|
527
532
|
## OpenAPI и экспорт схем
|
|
528
533
|
|
|
529
|
-
Экспорт использует OpenAPI 3.0.3. Добавьте `openapi: {}` и `
|
|
534
|
+
Экспорт использует OpenAPI 3.0.3. Добавьте `openapi: {}`, `database.schema` и `package.source`, чтобы получать спецификацию по HTTP на `/openapi.json`. Путь меняется через `openapi.endpoint`. Поля OpenAPI `info.title`, `info.version` и необязательное `info.description` берутся из настроенного `package.json`. Спецификацию можно открыть в Swagger UI или импортировать в API-клиент.
|
|
530
535
|
|
|
531
536
|
Для сохранения схем задайте пути экспорта:
|
|
532
537
|
|
|
@@ -536,6 +541,7 @@ export default {
|
|
|
536
541
|
database: { source: './database.json', schema: './schema.json' },
|
|
537
542
|
openapi: { target: './generated/openapi.yaml' },
|
|
538
543
|
graphql: { target: './generated/schema.graphql' },
|
|
544
|
+
package: { source: './package.json' },
|
|
539
545
|
};
|
|
540
546
|
```
|
|
541
547
|
|
|
@@ -713,7 +719,7 @@ OpenAPI описывает маршруты auth, необязательную B
|
|
|
713
719
|
|
|
714
720
|
При включённом auth создавать записи может любой вошедший пользователь. Изменять, удалять и восстанавливать — владелец по `createdById` или пользователь с `isAdmin: true`. Записи без владельца изменяет только администратор. Его правки не меняют владельца. Правила действуют на вложенные записи, изменение ключей связей, каскады и восстановление. Ссылка на существующую запись без её изменения не требует владения ею. Каждая мутация атомарна: отказ сохраняет прежнее состояние всех затронутых записей.
|
|
715
721
|
|
|
716
|
-
REST возвращает 401 при отсутствии действительного токена и 403 при недостатке прав. GraphQL проверяет мутации по тем же правилам и возвращает коды `UNAUTHENTICATED` или `FORBIDDEN`; токен получают через REST-вход и передают в `Authorization: Bearer
|
|
722
|
+
REST возвращает 401 при отсутствии действительного токена и 403 при недостатке прав. GraphQL проверяет мутации по тем же правилам и возвращает коды `UNAUTHENTICATED` или `FORBIDDEN`; токен получают через REST-вход и передают в `Authorization: Bearer <token>`. GraphQL-запросы чтения, OPTIONS и все операции с файлами остаются открытыми.
|
|
717
723
|
|
|
718
724
|
## Файлы
|
|
719
725
|
|
|
@@ -765,13 +771,13 @@ Content-Type: image/jpeg
|
|
|
765
771
|
Сочетание `directory` и `name` идентифицирует файл. Повторная загрузка по существующему пути возвращает `409`. Чтобы заменить файл, передайте `Content-Override: true`; успешная перезапись возвращает `200`. Сервер поддерживает следующие файловые маршруты:
|
|
766
772
|
|
|
767
773
|
```text
|
|
768
|
-
POST /_files/storage
|
|
769
|
-
GET /_files/storage/*
|
|
770
|
-
PATCH /_files/storage/*
|
|
771
|
-
DELETE /_files/storage/*
|
|
774
|
+
POST /_files/storage Upload or replace a file
|
|
775
|
+
GET /_files/storage/* Return file contents inline
|
|
776
|
+
PATCH /_files/storage/* Rename or move a file
|
|
777
|
+
DELETE /_files/storage/* Delete a file
|
|
772
778
|
|
|
773
|
-
GET /_files/metadata/*
|
|
774
|
-
GET /_files/download/*
|
|
779
|
+
GET /_files/metadata/* Return file metadata as JSON
|
|
780
|
+
GET /_files/download/* Download a file as an attachment
|
|
775
781
|
```
|
|
776
782
|
|
|
777
783
|
Для переименования, перемещения либо обеих операций отправьте JSON-объект. Нужно указать хотя бы одно поле:
|
|
@@ -808,7 +814,7 @@ await server.listen();
|
|
|
808
814
|
|
|
809
815
|
Методы `openapi()` и `graphql()` возвращают схемы и требуют `database.schema`. `fastify()` возвращает экземпляр сервера для настройки и запуска. База и включённые сервисы инициализируются при `ready()`, `listen()` или первом `inject()`; ошибка инициализации останавливает запуск.
|
|
810
816
|
|
|
811
|
-
`createServer(config)` принимает
|
|
817
|
+
`createServer(config)` принимает тот же объект конфигурации, что и CLI. При наличии `openapi` или `graphql` обязателен `package.source`. Для методов `openapi()` и `graphql()` нужна соответствующая секция. Методы возвращают схему и не записывают файлы.
|
|
812
818
|
|
|
813
819
|
Эти функции доступны и через общий импорт `@kollors/deep-json-server`. Адаптеры сервера загружаются при включении. Генераторы можно использовать отдельно:
|
|
814
820
|
|
|
@@ -816,7 +822,7 @@ await server.listen();
|
|
|
816
822
|
import { generateOpenapi, writeOpenapi } from '@kollors/deep-json-server/openapi';
|
|
817
823
|
import { generateGraphql, writeGraphql } from '@kollors/deep-json-server/graphql';
|
|
818
824
|
|
|
819
|
-
const document = await generateOpenapi('./schema.json', { files: true });
|
|
825
|
+
const document = await generateOpenapi('./schema.json', { files: true, packagePath: './package.json' });
|
|
820
826
|
const sdl = await generateGraphql('./schema.json');
|
|
821
827
|
await writeOpenapi(document, './generated/openapi.yaml');
|
|
822
828
|
await writeGraphql(sdl, './generated/schema.graphql');
|
|
@@ -824,11 +830,11 @@ await writeGraphql(sdl, './generated/schema.graphql');
|
|
|
824
830
|
|
|
825
831
|
Отдельные генераторы принимают путь или объект схемы и не требуют конфигурации сервера. Выбранная функция задаёт формат по умолчанию; `api` у модели может его ограничить. `timestamps` и `softDelete` берутся из схемы. Опция `{ auth: true }` добавляет поля владельца и `actions`; OpenAPI также описывает маршруты auth и требования токена. `hashPassword()` доступна и через общий импорт пакета.
|
|
826
832
|
|
|
827
|
-
`generateOpenapi()`
|
|
833
|
+
Для `generateOpenapi()` обязателен `packagePath`; дополнительно доступны `host`, `port`, `pageSize` и `maxPageSize`. Метаданные OpenAPI читаются из указанного пакета. Вместо пути можно передать объект схемы. Сервер и генераторы работают с собственной копией модели. Размеры страниц должны быть положительными целыми числами; `pageSize` не может превышать `maxPageSize`.
|
|
828
834
|
|
|
829
835
|
## Хранение данных
|
|
830
836
|
|
|
831
|
-
Изменения выполняются последовательно внутри экземпляра сервера и проверяются на копии данных до сохранения. Для одного файла базы используйте один процесс сервера. Счётчики `increment` хранятся рядом с базой в
|
|
837
|
+
Изменения выполняются последовательно внутри экземпляра сервера и проверяются на копии данных до сохранения. Для одного файла базы используйте один процесс сервера. Счётчики `increment` хранятся рядом с базой в `<database path>.counters.json`; сохраняйте этот файл вместе с базой. Номера резервируются до записи данных: сбой может оставить пропуск, но не приводит к повторной выдаче номера.
|
|
832
838
|
|
|
833
839
|
## Разработка
|
|
834
840
|
|
|
@@ -839,8 +845,8 @@ npm ci
|
|
|
839
845
|
npm run verify
|
|
840
846
|
```
|
|
841
847
|
|
|
842
|
-
|
|
848
|
+
`npm run verify` проверяет типы, стиль кода, покрытие тестами и установку пакета из архива.
|
|
843
849
|
|
|
844
|
-
Для публикации предварительной версии обновите номер в `package.json`, `package-lock.json` и `src/core/constants.ts`, затем отправьте коммит в `main`. GitHub Actions создаст тег `v
|
|
850
|
+
Для публикации предварительной версии обновите номер в `package.json`, `package-lock.json` и `src/core/constants.ts`, затем отправьте коммит в `main`. GitHub Actions создаст тег `v<version>` и опубликует пакет через trusted publishing в канал `alpha`, `beta` или `rc`. Стабильные версии публикуются в `latest` из явно отправленного тега версии.
|
|
845
851
|
|
|
846
852
|
Лицензия: MIT.
|