@kollors/deep-json-server 0.7.0 → 0.8.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/README.md +19 -16
- package/README.ru.md +20 -17
- package/dist/bin/deep-json-server.d.ts +2 -0
- package/dist/bin/deep-json-server.js +11 -0
- package/dist/bin/deep-json-server.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/src/cli.d.ts +4 -0
- package/dist/src/cli.js +80 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +54 -0
- package/dist/src/config.js +145 -0
- package/dist/src/config.js.map +1 -0
- package/{src → dist/src}/constants.js +1 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/database.d.ts +20 -0
- package/dist/src/database.js +136 -0
- package/dist/src/database.js.map +1 -0
- package/dist/src/files/contract.d.ts +67 -0
- package/dist/src/files/contract.js +106 -0
- package/dist/src/files/contract.js.map +1 -0
- package/dist/src/files/disk-store.d.ts +5 -0
- package/dist/src/files/disk-store.js +313 -0
- package/dist/src/files/disk-store.js.map +1 -0
- package/dist/src/files/index.d.ts +5 -0
- package/dist/src/files/index.js +6 -0
- package/dist/src/files/index.js.map +1 -0
- package/dist/src/files/memory-store.d.ts +3 -0
- package/dist/src/files/memory-store.js +80 -0
- package/dist/src/files/memory-store.js.map +1 -0
- package/dist/src/files/routes.d.ts +6 -0
- package/dist/src/files/routes.js +77 -0
- package/dist/src/files/routes.js.map +1 -0
- package/dist/src/openapi/config.d.ts +11 -0
- package/dist/src/openapi/config.js +204 -0
- package/dist/src/openapi/config.js.map +1 -0
- package/dist/src/openapi/document.d.ts +9 -0
- package/dist/src/openapi/document.js +338 -0
- package/dist/src/openapi/document.js.map +1 -0
- package/dist/src/openapi/index.d.ts +10 -0
- package/dist/src/openapi/index.js +27 -0
- package/dist/src/openapi/index.js.map +1 -0
- package/dist/src/openapi/inference.d.ts +14 -0
- package/dist/src/openapi/inference.js +145 -0
- package/dist/src/openapi/inference.js.map +1 -0
- package/dist/src/query/filter.d.ts +6 -0
- package/dist/src/query/filter.js +248 -0
- package/dist/src/query/filter.js.map +1 -0
- package/{src → dist/src}/query/index.js +1 -0
- package/dist/src/query/index.js.map +1 -0
- package/dist/src/query/pagination.d.ts +11 -0
- package/dist/src/query/pagination.js +28 -0
- package/dist/src/query/pagination.js.map +1 -0
- package/dist/src/query/sort.d.ts +1 -0
- package/dist/src/query/sort.js +54 -0
- package/dist/src/query/sort.js.map +1 -0
- package/dist/src/relation-metadata.d.ts +10 -0
- package/dist/src/relation-metadata.js +32 -0
- package/dist/src/relation-metadata.js.map +1 -0
- package/dist/src/relations.d.ts +12 -0
- package/dist/src/relations.js +155 -0
- package/dist/src/relations.js.map +1 -0
- package/dist/src/server.d.ts +13 -0
- package/dist/src/server.js +188 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/types.d.ts +52 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils.d.ts +20 -0
- package/dist/src/utils.js +63 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +17 -16
- package/bin/deep-json-server.js +0 -11
- package/index.js +0 -12
- package/src/cli.js +0 -91
- package/src/config.js +0 -203
- package/src/database.js +0 -148
- package/src/files.js +0 -633
- package/src/openapi/config.js +0 -124
- package/src/openapi/document.js +0 -394
- package/src/openapi/index.js +0 -36
- package/src/openapi/inference.js +0 -187
- package/src/query/filter.js +0 -283
- package/src/query/pagination.js +0 -44
- package/src/query/sort.js +0 -63
- package/src/relation-metadata.js +0 -41
- package/src/relations.js +0 -173
- package/src/server.js +0 -250
- package/src/utils.js +0 -84
- package/types/index.d.ts +0 -21
- package/types/src/config.d.ts +0 -73
- package/types/src/database.d.ts +0 -33
- package/types/src/files.d.ts +0 -64
- package/types/src/openapi/config.d.ts +0 -3
- package/types/src/openapi/document.d.ts +0 -11
- package/types/src/openapi/index.d.ts +0 -9
- package/types/src/openapi/inference.d.ts +0 -9
- package/types/src/query/filter.d.ts +0 -3
- package/types/src/query/pagination.d.ts +0 -8
- package/types/src/query/sort.d.ts +0 -1
- package/types/src/relation-metadata.d.ts +0 -9
- package/types/src/relations.d.ts +0 -3
- package/types/src/server.d.ts +0 -14
- package/types/src/utils.d.ts +0 -18
- /package/{types → dist}/src/constants.d.ts +0 -0
- /package/{types → dist}/src/query/index.d.ts +0 -0
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[GitHub](https://github.com/kollors/deep-json-server) | [npm](https://www.npmjs.com/package/@kollors/deep-json-server)
|
|
6
6
|
|
|
7
|
-
A small REST mock server with CRUD, pagination,
|
|
7
|
+
A small REST API mock server with CRUD, pagination, nested data filtering, relation embedding through `_embed`, binary files, and OpenAPI generation. Data can be stored in JSON files or memory, and relations are inferred from field names such as `countryId`, `genreIds`, and `publisherIds`.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -53,7 +53,7 @@ The API is available at `http://127.0.0.1:4001` by default. For example, `GET ht
|
|
|
53
53
|
|
|
54
54
|
## Configuration and startup
|
|
55
55
|
|
|
56
|
-
Create the ESM module `server.config.js`. The example below
|
|
56
|
+
Create the ESM module `server.config.js`. The example below shows settings for every feature:
|
|
57
57
|
|
|
58
58
|
```js
|
|
59
59
|
import process from 'node:process';
|
|
@@ -71,6 +71,7 @@ export default {
|
|
|
71
71
|
path: 'mock/openapi-schema.yaml',
|
|
72
72
|
},
|
|
73
73
|
server: {
|
|
74
|
+
cors: true,
|
|
74
75
|
host: '127.0.0.1',
|
|
75
76
|
logger: true,
|
|
76
77
|
maxFileSize: 100 * 1024 * 1024,
|
|
@@ -91,6 +92,7 @@ Configuration keys:
|
|
|
91
92
|
| `files.metadata` | Together with `files.directory` | JSON file containing file metadata on disk |
|
|
92
93
|
| `files.data` | Instead of the `directory` and `metadata` pair | In-memory files with `Uint8Array` contents |
|
|
93
94
|
| `openapi.path` | Required by the `--openapi` and `--openapi-only` CLI flags | Generated OpenAPI YAML file; the programmatic API can return a document without this path |
|
|
95
|
+
| `server.cors` | No | Enables permissive CORS headers and `OPTIONS` routes; defaults to `true` |
|
|
94
96
|
| `server.host` | No | Host used by the CLI, `server.openapi()`, and argument-less `server.fastify().listen()`; defaults to `127.0.0.1` |
|
|
95
97
|
| `server.logger` | No | Fastify logger settings; defaults to `true` |
|
|
96
98
|
| `server.maxFileSize` | No | Maximum uploaded-file size in bytes when file routes are enabled; defaults to 100 MiB |
|
|
@@ -219,7 +221,7 @@ DELETE /movies/:id
|
|
|
219
221
|
|
|
220
222
|
`POST` generates a string ID. `PUT` completely replaces the selected record, while `PATCH` updates only supplied fields; both preserve the existing ID and its type. An `id` supplied in any request body cannot override the server-controlled ID. All write operations — `POST`, `PUT`, `PATCH` and `DELETE` — are serialized; disk storage persists them in JSON, while memory storage retains them until the process exits.
|
|
221
223
|
|
|
222
|
-
The database file must exist before startup. Resource names may contain Latin letters, numbers, `_` and `-`, and must start with a letter. Every resource is an array of JSON objects. Every record must have a non-empty string or finite numeric `id`; IDs must be unique within a resource when compared as strings, so `1` and `"1"` cannot coexist. The server rereads the file before every GET and write operation, so valid
|
|
224
|
+
The database file must exist before startup. Resource names may contain Latin letters, numbers, `_` and `-`, and must start with a letter. Every resource is an array of JSON objects. Every record must have a non-empty string or finite numeric `id`; IDs must be unique within a resource when compared as strings, so `1` and `"1"` cannot coexist. All nested values must be JSON-compatible: finite numbers, strings, booleans, `null`, arrays, and plain objects. The server rereads the file before every resource GET and write operation, so valid edits to existing resources become visible immediately. Resource names and routes are discovered at startup; restart the server after adding, removing, or renaming a top-level resource.
|
|
223
225
|
|
|
224
226
|
Successful writes return the created, replaced, updated or deleted record. Errors use an appropriate HTTP status and this JSON shape:
|
|
225
227
|
|
|
@@ -301,7 +303,7 @@ GET /movies?title:contains=ardenia
|
|
|
301
303
|
|
|
302
304
|
Simple filter values recognize JSON primitives: numbers, `true`, `false` and `null`. Values with leading zeroes, such as `001`, remain strings. Unknown operators, invalid logical conditions and filter paths that do not exist in a non-empty resource return `400`.
|
|
303
305
|
|
|
304
|
-
|
|
306
|
+
Different simple query filters are combined with `AND`. Repeating the same equality filter selects any of its values, so `GET /movies?id=1&id=2` is equivalent to `GET /movies?id:in=1,2`. For an `in` filter, values are separated with commas. On an array field, `in` means that at least one field element matches at least one supplied value. `every` returns `true` for an empty array, while `some` returns `false`.
|
|
305
307
|
|
|
306
308
|
If `_where` is present, it is the complete filter and other simple filter parameters are ignored. The examples show readable JSON; an HTTP client must URL-encode `_where` when constructing the URL manually, for example with `encodeURIComponent(JSON.stringify(where))`.
|
|
307
309
|
|
|
@@ -340,9 +342,9 @@ Relations are inferred by convention. A field named `<relation>Id` creates a sin
|
|
|
340
342
|
- `publisherIds` points to `publishers`;
|
|
341
343
|
- `parentIds` points back to the current resource when `_embed=parents` is requested; `_embed=children` resolves the reverse self-relation.
|
|
342
344
|
|
|
343
|
-
Reverse relations use the source resource name. For example, `_embed=users` on a country finds users whose nested data contains the corresponding `countryId`.
|
|
345
|
+
Reverse relations use the source resource name. For example, `_embed=users` on a country finds users whose nested data contains the corresponding `countryId`. Relations are resolved when requested, but referential integrity is not enforced when data is written.
|
|
344
346
|
|
|
345
|
-
|
|
347
|
+
Explicit `...Id` and `...Ids` fields determine relations. If a record also contains an outdated embedded value, `_embed` replaces that response property with the current related record. A missing related record becomes `null` for a single relation or is omitted from the resulting array for a collection relation. Per-request ID indexes are created only for resources used by the current relation lookup.
|
|
346
348
|
|
|
347
349
|
## Files
|
|
348
350
|
|
|
@@ -403,9 +405,9 @@ Content-Type: application/json
|
|
|
403
405
|
}
|
|
404
406
|
```
|
|
405
407
|
|
|
406
|
-
`PATCH` returns the updated metadata with status `200`; a
|
|
408
|
+
`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.
|
|
407
409
|
|
|
408
|
-
In disk mode, the binary is stored at `<files.directory>/<directory>/<name>`. The metadata file contains only `directory`, `mimeType`, and `name`; `size` is read from the actual file, while response URLs are computed. The server creates directories automatically
|
|
410
|
+
In disk mode, the binary is stored at `<files.directory>/<directory>/<name>`. The metadata file contains only `directory`, `mimeType`, and `name`; `size` is read from the actual file, while response URLs are computed. The server creates directories automatically and keeps validated metadata in memory while running. Use a disk-backed database and file storage from only one server process at a time, and do not edit stored files or metadata until that process stops. Paths below `files.directory` may not contain symbolic links, and file names are restricted to values that are portable across supported operating systems. The metadata file may be absent initially and is created on the first upload. Metadata created by versions before this path-based API is not compatible with the new format.
|
|
409
411
|
|
|
410
412
|
The upload is raw binary rather than `multipart/form-data`, so `XMLHttpRequest.upload.onprogress` can report progress while the browser sends a `File` directly with `xhr.send(file)`. 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.
|
|
411
413
|
|
|
@@ -459,7 +461,7 @@ To include file routes in the document, configure the `files` section and add `-
|
|
|
459
461
|
|
|
460
462
|
The generator infers resources and field types from all database records. Every inferred field is optional by default, while the top-level `id` is always required in response schemas and is omitted from create and update request schemas. Add other required fields to `required`. A nested required path marks that nested property as required; it does not automatically make every parent path required, so list the parent separately when necessary.
|
|
461
463
|
|
|
462
|
-
Different value types are inferred independently and combined through `oneOf
|
|
464
|
+
Different non-overlapping value types are inferred independently and combined through `oneOf`; mixed integers and decimal numbers are represented by one `number` schema. Configuration is validated before generation: `$info`, resource and component names, supported `properties` keywords and their value types are checked, while paths from `required` and `formats` must exist in the resulting schema. Explicit component names may contain ASCII letters, digits, dots, underscores, and hyphens.
|
|
463
465
|
|
|
464
466
|
Use `properties` to describe fields that cannot be inferred, particularly for an empty resource. Explicit properties are merged with inferred properties:
|
|
465
467
|
|
|
@@ -493,7 +495,7 @@ Use `name` when a resource needs an explicit schema name instead of the automati
|
|
|
493
495
|
}
|
|
494
496
|
```
|
|
495
497
|
|
|
496
|
-
The generated document describes CRUD endpoints, pagination, sorting,
|
|
498
|
+
The generated document describes CRUD endpoints, pagination, sorting, nested data filters, `_embed`, and both direct and reverse response relations inferred from `...Id` and `...Ids` fields. When `--files` is present, it also describes raw binary upload, download and deletion endpoints for arbitrary media types. A numeric database ID is described as `integer | string`, because a later `POST` creates a string ID in the same resource. Generation rejects duplicate schema names, operation IDs, and invalid schema overrides before producing a document. The document can be used as input for tools such as RTK Query OpenAPI Codegen. OpenAPI is generated only with `--openapi` or `--openapi-only`; normal server startup does not rewrite the file.
|
|
497
499
|
|
|
498
500
|
During normal startup, request bodies are validated against the same inferred and configured schemas. `POST` and `PUT` enforce configured required fields; `PATCH` validates only fields that are actually supplied. `formats` and `properties` apply to all three methods. Unlisted additional object fields remain allowed. Invalid bodies return `400`.
|
|
499
501
|
|
|
@@ -515,6 +517,7 @@ const config = {
|
|
|
515
517
|
path: 'mock/openapi-schema.yaml',
|
|
516
518
|
},
|
|
517
519
|
server: {
|
|
520
|
+
cors: true,
|
|
518
521
|
host: '127.0.0.1',
|
|
519
522
|
logger: false,
|
|
520
523
|
maxFileSize: 100 * 1024 * 1024,
|
|
@@ -563,17 +566,17 @@ console.log(memoryResponse.json());
|
|
|
563
566
|
await memoryFastify.close();
|
|
564
567
|
```
|
|
565
568
|
|
|
566
|
-
`createServer()` accepts exactly the same config shape as `server.config.js`. It loads and clones the
|
|
569
|
+
`createServer()` accepts exactly the same config shape as `server.config.js`. It loads and clones the database, schema, and file storage, then returns an object with two methods:
|
|
567
570
|
|
|
568
|
-
|
|
|
569
|
-
| --- | --- |
|
|
571
|
+
| Method | Purpose |
|
|
572
|
+
| --- | --- |
|
|
570
573
|
| `server.fastify()` | Lazily creates and caches the real Fastify instance; every native method remains available, and argument-less `listen()` uses `server.host` and `server.port` |
|
|
571
574
|
| `server.openapi()` | Returns an OpenAPI document and also writes it when `openapi.path` is configured |
|
|
572
575
|
|
|
573
|
-
File routes are enabled programmatically when a `files` section is present. The second argument has the shape `{ files?: boolean }`: pass `{ files: false }` to keep a configured store disabled, or `{ files: true }` to require a `files` section and enable the routes. `server.openapi()` uses the same
|
|
576
|
+
File routes are enabled programmatically when a `files` section is present. The second argument has the shape `{ files?: boolean }`: pass `{ files: false }` to keep a configured store disabled, or `{ files: true }` to require a `files` section and enable the routes. `server.openapi()` uses the same file-route setting as `server.fastify()`.
|
|
574
577
|
|
|
575
|
-
An argument-less `server.fastify().listen()` uses `server.host` and `server.port`, falling back to `127.0.0.1:4001`. Explicit `listen(options)` values take precedence. Relative paths passed directly to `createServer()` resolve from the current working directory; paths loaded from `server.config.js` resolve from the config directory. The package includes generated TypeScript declarations for the
|
|
578
|
+
An argument-less `server.fastify().listen()` uses `server.host` and `server.port`, falling back to `127.0.0.1:4001`. Explicit `listen(options)` values take precedence. Relative paths passed directly to `createServer()` resolve from the current working directory; paths loaded from `server.config.js` resolve from the config directory. The package includes generated TypeScript declarations for the returned object and every config variant.
|
|
576
579
|
|
|
577
580
|
## Scope and security
|
|
578
581
|
|
|
579
|
-
Deep JSON Server is intended for local development and automated tests. It has no authentication or authorization, allows CORS from every origin, persists accepted writes when disk storage is configured and does not enforce referential integrity. Keep the default loopback host unless the surrounding environment provides its own access controls; do not expose the server or file routes to an untrusted network.
|
|
582
|
+
Deep JSON Server is intended for local development and automated tests. It has no authentication or authorization, allows CORS from every origin by default, persists accepted writes when disk storage is configured and does not enforce referential integrity. Set `server.cors` to `false` to disable the built-in CORS headers and `OPTIONS` routes. Keep the default loopback host unless the surrounding environment provides its own access controls; do not expose the server or file routes to an untrusted network.
|
package/README.ru.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[GitHub](https://github.com/kollors/deep-json-server) | [npm](https://www.npmjs.com/package/@kollors/deep-json-server)
|
|
6
6
|
|
|
7
|
-
Небольшой
|
|
7
|
+
Небольшой сервер для имитации REST API с CRUD, пагинацией, фильтрацией вложенных данных, подстановкой связанных записей через `_embed`, бинарными файлами и генерацией OpenAPI. Данные могут храниться в JSON-файлах или памяти, а связи определяются по именам полей: `countryId`, `genreIds`, `publisherIds` и так далее.
|
|
8
8
|
|
|
9
9
|
## Установка
|
|
10
10
|
|
|
@@ -53,7 +53,7 @@ npx deep-json-server server.config.js
|
|
|
53
53
|
|
|
54
54
|
## Конфигурация и запуск
|
|
55
55
|
|
|
56
|
-
Создайте ESM-модуль `server.config.js`. В примере ниже
|
|
56
|
+
Создайте ESM-модуль `server.config.js`. В примере ниже показаны настройки всех возможностей:
|
|
57
57
|
|
|
58
58
|
```js
|
|
59
59
|
import process from 'node:process';
|
|
@@ -71,6 +71,7 @@ export default {
|
|
|
71
71
|
path: 'mock/openapi-schema.yaml',
|
|
72
72
|
},
|
|
73
73
|
server: {
|
|
74
|
+
cors: true,
|
|
74
75
|
host: '127.0.0.1',
|
|
75
76
|
logger: true,
|
|
76
77
|
maxFileSize: 100 * 1024 * 1024,
|
|
@@ -91,6 +92,7 @@ export default {
|
|
|
91
92
|
| `files.metadata` | Вместе с `files.directory` | JSON-файл с метаданными файлов на диске |
|
|
92
93
|
| `files.data` | Вместо пары `directory` и `metadata` | Файлы в памяти с содержимым в `Uint8Array` |
|
|
93
94
|
| `openapi.path` | Обязателен для CLI-флагов `--openapi` и `--openapi-only` | Генерируемый YAML-файл OpenAPI; программный API может вернуть документ без этого пути |
|
|
95
|
+
| `server.cors` | Необязателен | Включает разрешающие CORS-заголовки и маршруты `OPTIONS`; по умолчанию `true` |
|
|
94
96
|
| `server.host` | Необязателен | Адрес для CLI, `server.openapi()` и вызова `server.fastify().listen()` без аргументов; по умолчанию `127.0.0.1` |
|
|
95
97
|
| `server.logger` | Необязателен | Настройки логгера Fastify; по умолчанию `true` |
|
|
96
98
|
| `server.maxFileSize` | Необязателен | Максимальный размер загружаемого файла в байтах при включённых файловых маршрутах; по умолчанию 100 МиБ |
|
|
@@ -219,7 +221,7 @@ DELETE /movies/:id
|
|
|
219
221
|
|
|
220
222
|
`POST` генерирует строковый ID. `PUT` полностью заменяет выбранную запись, а `PATCH` изменяет только переданные поля; обе операции сохраняют существующий ID и его тип. Поле `id` в теле любого запроса не может переопределить ID, которым управляет сервер. Все операции записи — `POST`, `PUT`, `PATCH` и `DELETE` — выполняются последовательно; дисковое хранилище записывает их в JSON, а хранилище в памяти сохраняет до завершения процесса.
|
|
221
223
|
|
|
222
|
-
Файл базы должен существовать до запуска. Имена ресурсов могут содержать латинские буквы, цифры, `_` и `-` и должны начинаться с буквы. Каждый ресурс является массивом JSON-объектов. У каждой записи должен быть непустой строковый или конечный числовой `id`; ID должны быть уникальны внутри ресурса при сравнении как строки, поэтому `1` и `"1"` не могут существовать одновременно. Перед каждым GET-запросом и изменением сервер заново читает файл, поэтому корректные
|
|
224
|
+
Файл базы должен существовать до запуска. Имена ресурсов могут содержать латинские буквы, цифры, `_` и `-` и должны начинаться с буквы. Каждый ресурс является массивом JSON-объектов. У каждой записи должен быть непустой строковый или конечный числовой `id`; ID должны быть уникальны внутри ресурса при сравнении как строки, поэтому `1` и `"1"` не могут существовать одновременно. Все вложенные значения должны быть совместимы с JSON: конечные числа, строки, логические значения, `null`, массивы и обычные объекты. Перед каждым GET-запросом к ресурсу и изменением сервер заново читает файл, поэтому корректные правки существующих ресурсов становятся видны сразу. Имена ресурсов и маршруты определяются при запуске; после добавления, удаления или переименования массива верхнего уровня перезапустите сервер.
|
|
223
225
|
|
|
224
226
|
Успешная операция записи возвращает созданную, заменённую, обновлённую или удалённую запись. Ошибки используют подходящий HTTP-статус и следующий JSON-формат:
|
|
225
227
|
|
|
@@ -301,7 +303,7 @@ GET /movies?title:contains=тени
|
|
|
301
303
|
|
|
302
304
|
В простых фильтрах распознаются JSON-примитивы: числа, `true`, `false` и `null`. Значения с ведущими нулями, например `001`, остаются строками. Неизвестные операторы, некорректные логические условия и отсутствующие в непустом ресурсе пути фильтра возвращают `400`.
|
|
303
305
|
|
|
304
|
-
|
|
306
|
+
Разные простые query-фильтры объединяются через `AND`. Повтор одного фильтра равенства выбирает любое из его значений, поэтому `GET /movies?id=1&id=2` равнозначен `GET /movies?id:in=1,2`. Для оператора `in` значения перечисляются через запятую. Для поля-массива `in` означает, что хотя бы один элемент поля совпадает хотя бы с одним переданным значением. `every` для пустого массива возвращает `true`, а `some` — `false`.
|
|
305
307
|
|
|
306
308
|
Если передан `_where`, он становится полным фильтром, а остальные простые параметры фильтрации игнорируются. В примерах JSON оставлен читаемым; при ручном формировании URL HTTP-клиент должен закодировать значение `_where`, например через `encodeURIComponent(JSON.stringify(where))`.
|
|
307
309
|
|
|
@@ -332,7 +334,7 @@ GET /genres/2?_embed=parents.parents
|
|
|
332
334
|
GET /countries/1?_embed=users
|
|
333
335
|
```
|
|
334
336
|
|
|
335
|
-
Связи определяются по
|
|
337
|
+
Связи определяются по именам полей. Поле `<relation>Id` создаёт одиночную связь, а `<relation>Ids` — связь с коллекцией. Имя связи сопоставляется с ресурсом верхнего уровня напрямую или через его форму в единственном числе. Например:
|
|
336
338
|
|
|
337
339
|
- `countryId` ссылается на `countries`;
|
|
338
340
|
- `userId` ссылается на `users`, если запрошена связь `user`;
|
|
@@ -340,9 +342,9 @@ GET /countries/1?_embed=users
|
|
|
340
342
|
- `publisherIds` ссылается на `publishers`;
|
|
341
343
|
- `parentIds` ссылается на тот же ресурс, если запрошена связь `_embed=parents`; `_embed=children` загружает обратную связь с дочерними записями.
|
|
342
344
|
|
|
343
|
-
Имя обратной связи совпадает с именем исходного ресурса. Например, `_embed=users` у страны находит пользователей, во вложенных данных которых указан соответствующий `countryId`.
|
|
345
|
+
Имя обратной связи совпадает с именем исходного ресурса. Например, `_embed=users` у страны находит пользователей, во вложенных данных которых указан соответствующий `countryId`. Сервер получает связи по запросу, но не проверяет ссылочную целостность при записи данных.
|
|
344
346
|
|
|
345
|
-
|
|
347
|
+
Явные поля `...Id` и `...Ids` определяют связи. Если в записи также сохранено устаревшее вложенное значение, `_embed` заменяет это свойство ответа актуальной связанной записью. Если связанная запись для одиночной связи не найдена, результатом будет `null`; отсутствующие связанные записи коллекции не попадут в итоговый массив. ID-индексы создаются только для ресурсов, используемых при поиске связей в текущем запросе.
|
|
346
348
|
|
|
347
349
|
## Файлы
|
|
348
350
|
|
|
@@ -403,9 +405,9 @@ Content-Type: application/json
|
|
|
403
405
|
}
|
|
404
406
|
```
|
|
405
407
|
|
|
406
|
-
`PATCH` возвращает обновлённые метаданные со статусом `200`;
|
|
408
|
+
`PATCH` возвращает обновлённые метаданные со статусом `200`; если по новому пути уже существует файл, сервер возвращает `409`. `DELETE` отвечает статусом `204` без тела. Если файл не найден, любая операция по пути возвращает `404`. Пути в URL задаются относительно `files.directory`, а все возвращаемые URL — относительно адреса сервера.
|
|
407
409
|
|
|
408
|
-
При хранении на диске бинарный файл находится по пути `<files.directory>/<directory>/<name>`. Файл метаданных содержит только `directory`, `mimeType` и `name`; `size` считывается у фактического файла, а URL вычисляются.
|
|
410
|
+
При хранении на диске бинарный файл находится по пути `<files.directory>/<directory>/<name>`. Файл метаданных содержит только `directory`, `mimeType` и `name`; `size` считывается у фактического файла, а URL вычисляются. Используйте дисковую базу и файловое хранилище только из одного процесса сервера одновременно и не редактируйте сохранённые файлы или метаданные до его остановки. Сервер автоматически создаёт директории, пути внутри `files.directory` не могут содержать символические ссылки, а имена файлов ограничены переносимыми между поддерживаемыми операционными системами значениями. Изначально файл метаданных может отсутствовать: он создаётся при первой загрузке. Метаданные, созданные версиями до перехода на адресацию по пути, несовместимы с новым форматом.
|
|
409
411
|
|
|
410
412
|
Используется бинарное тело запроса, а не `multipart/form-data`, поэтому `XMLHttpRequest.upload.onprogress` может показывать прогресс при непосредственной отправке `File` через `xhr.send(file)`. Максимальный размер по умолчанию равен 100 МиБ и настраивается через `server.maxFileSize`. Отсутствующие или небезопасные заголовки и пути возвращают `400`, превышение лимита — `413`, а отсутствующий, некорректный или не поддерживаемый Fastify `Content-Type` — `400` либо `415` в зависимости от этапа проверки.
|
|
411
413
|
|
|
@@ -459,7 +461,7 @@ deep-json-server --openapi-only server.config.js
|
|
|
459
461
|
|
|
460
462
|
Генератор определяет ресурсы и типы полей по всем записям базы. По умолчанию все найденные поля необязательные, а поле `id` верхнего уровня всегда обязательное в схемах ответа и исключается из схем создания и обновления. Остальные обязательные поля перечисляются в `required`. Вложенный обязательный путь делает обязательным само вложенное свойство, но не все его родительские пути; при необходимости родителя нужно перечислить отдельно.
|
|
461
463
|
|
|
462
|
-
Разные типы значений определяются независимо и объединяются через `oneOf`. Перед генерацией проверяются `$info`, имена ресурсов и
|
|
464
|
+
Разные непересекающиеся типы значений определяются независимо и объединяются через `oneOf`; сочетание целых и дробных чисел описывается одной схемой `number`. Перед генерацией проверяются `$info`, имена ресурсов и компонентов, поддерживаемые ключи `properties` и типы их значений; пути из `required` и `formats` должны существовать в итоговой схеме. Явные имена компонентов могут содержать латинские буквы, цифры, точки, подчёркивания и дефисы.
|
|
463
465
|
|
|
464
466
|
Используйте `properties`, чтобы описать поля, которые невозможно определить автоматически, особенно у пустого ресурса. Явно заданные свойства объединяются с найденными автоматически:
|
|
465
467
|
|
|
@@ -493,7 +495,7 @@ deep-json-server --openapi-only server.config.js
|
|
|
493
495
|
}
|
|
494
496
|
```
|
|
495
497
|
|
|
496
|
-
В сгенерированном документе описаны CRUD
|
|
498
|
+
В сгенерированном документе описаны CRUD-маршруты, пагинация, сортировка, фильтрация вложенных данных, `_embed`, а также прямые и обратные связи в ответах, определённые по полям `...Id` и `...Ids`. При наличии `--files` в него также добавляются маршруты бинарной загрузки, получения и удаления файлов с поддержкой произвольных MIME-типов. Числовой ID базы описывается как `integer | string`, поскольку последующий `POST` создаст строковый ID в том же ресурсе. До создания документа генератор отклоняет повторяющиеся имена схем и `operationId`, а также некорректные переопределения схем. Файл можно передать, например, в RTK Query OpenAPI Codegen. OpenAPI создаётся только с параметром `--openapi` или `--openapi-only`; обычный запуск сервера файл не перезаписывает.
|
|
497
499
|
|
|
498
500
|
При обычном запуске тела запросов проверяются по тем же автоматически выведенным и настроенным схемам. Для `POST` и `PUT` проверяются обязательные поля из `required`; `PATCH` проверяет только фактически переданные поля. Настройки `formats` и `properties` применяются ко всем трём методам. Не перечисленные дополнительные поля объекта остаются разрешёнными. Некорректные тела возвращают `400`.
|
|
499
501
|
|
|
@@ -515,6 +517,7 @@ const config = {
|
|
|
515
517
|
path: 'mock/openapi-schema.yaml',
|
|
516
518
|
},
|
|
517
519
|
server: {
|
|
520
|
+
cors: true,
|
|
518
521
|
host: '127.0.0.1',
|
|
519
522
|
logger: false,
|
|
520
523
|
maxFileSize: 100 * 1024 * 1024,
|
|
@@ -563,17 +566,17 @@ console.log(memoryResponse.json());
|
|
|
563
566
|
await memoryFastify.close();
|
|
564
567
|
```
|
|
565
568
|
|
|
566
|
-
`createServer()` принимает точно ту же структуру конфига, что и `server.config.js`. Функция загружает и клонирует
|
|
569
|
+
`createServer()` принимает точно ту же структуру конфига, что и `server.config.js`. Функция загружает и клонирует базу данных, схему и файловое хранилище, а затем возвращает объект с двумя методами:
|
|
567
570
|
|
|
568
|
-
|
|
|
569
|
-
| --- | --- |
|
|
571
|
+
| Метод | Назначение |
|
|
572
|
+
| --- | --- |
|
|
570
573
|
| `server.fastify()` | Лениво создаёт и кэширует настоящий экземпляр Fastify; все нативные методы доступны, а `listen()` без аргументов использует `server.host` и `server.port` |
|
|
571
574
|
| `server.openapi()` | Возвращает документ OpenAPI и дополнительно записывает его, если настроен `openapi.path` |
|
|
572
575
|
|
|
573
|
-
При программном использовании файловые маршруты включаются при наличии секции `files`. Сигнатура второго аргумента — `{ files?: boolean }`: передайте `{ files: false }`, чтобы оставить настроенное хранилище выключенным, или `{ files: true }`, чтобы потребовать секцию `files` и включить маршруты. `server.openapi()` использует
|
|
576
|
+
При программном использовании файловые маршруты включаются при наличии секции `files`. Сигнатура второго аргумента — `{ files?: boolean }`: передайте `{ files: false }`, чтобы оставить настроенное хранилище выключенным, или `{ files: true }`, чтобы потребовать секцию `files` и включить маршруты. `server.openapi()` использует ту же настройку файловых маршрутов, что и `server.fastify()`.
|
|
574
577
|
|
|
575
|
-
Вызов `server.fastify().listen()` без аргументов использует `server.host` и `server.port`, а при их отсутствии — `127.0.0.1:4001`. Явные параметры `listen(options)` имеют приоритет. Относительные пути, переданные напрямую в `createServer()`, вычисляются от текущей рабочей директории; пути из `server.config.js` — от директории конфига. Пакет содержит сгенерированные TypeScript-декларации
|
|
578
|
+
Вызов `server.fastify().listen()` без аргументов использует `server.host` и `server.port`, а при их отсутствии — `127.0.0.1:4001`. Явные параметры `listen(options)` имеют приоритет. Относительные пути, переданные напрямую в `createServer()`, вычисляются от текущей рабочей директории; пути из `server.config.js` — от директории конфига. Пакет содержит сгенерированные TypeScript-декларации возвращаемого объекта и всех вариантов конфигурации.
|
|
576
579
|
|
|
577
580
|
## Назначение и безопасность
|
|
578
581
|
|
|
579
|
-
Deep JSON Server предназначен для локальной разработки и автоматических тестов. В нём нет аутентификации и авторизации, CORS разрешён для любого источника, при дисковом хранилище принятые изменения сохраняются в настроенные файлы, а ссылочная целостность не проверяется. Оставляйте адрес loopback по умолчанию, если внешняя среда не предоставляет собственный контроль доступа; не открывайте сервер и файловые маршруты для недоверенной сети.
|
|
582
|
+
Deep JSON Server предназначен для локальной разработки и автоматических тестов. В нём нет аутентификации и авторизации, CORS по умолчанию разрешён для любого источника, при дисковом хранилище принятые изменения сохраняются в настроенные файлы, а ссылочная целостность не проверяется. Установите `server.cors: false`, чтобы отключить встроенные CORS-заголовки и маршруты `OPTIONS`. Оставляйте адрес loopback по умолчанию, если внешняя среда не предоставляет собственный контроль доступа; не открывайте сервер и файловые маршруты для недоверенной сети.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import { runCli } from '../src/cli.js';
|
|
4
|
+
try {
|
|
5
|
+
await runCli();
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
9
|
+
process.exitCode = 1;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=deep-json-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deep-json-server.js","sourceRoot":"","sources":["../../bin/deep-json-server.ts"],"names":[],"mappings":";AAEA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,IAAI,CAAC;IACH,MAAM,MAAM,EAAE,CAAC;AACjB,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { DatabaseConfig, DeepJsonServerConfig, FilesConfig, MemoryFile, OpenapiConfig, ServerConfig } from './src/config.js';
|
|
2
|
+
export type { FileMetadata, FileUpdate } from './src/files/contract.js';
|
|
3
|
+
export type { ServerFacade } from './src/server.js';
|
|
4
|
+
export { createServer } from './src/server.js';
|
|
5
|
+
export type { OpenapiDocument } from './src/types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { readServerConfig } from './config.js';
|
|
3
|
+
import { DEFAULT_HOST, DEFAULT_PORT } from './constants.js';
|
|
4
|
+
import { createServer } from './server.js';
|
|
5
|
+
const HELP_TEXT = `Deep JSON Server
|
|
6
|
+
|
|
7
|
+
Использование:
|
|
8
|
+
deep-json-server [--files] [--openapi | --openapi-only] <server.config.js>
|
|
9
|
+
|
|
10
|
+
Параметры:
|
|
11
|
+
--files Добавить файловые маршруты в сервер и OpenAPI
|
|
12
|
+
--openapi Сгенерировать OpenAPI и запустить сервер
|
|
13
|
+
--openapi-only Сгенерировать OpenAPI и завершить работу
|
|
14
|
+
--help Показать справку`;
|
|
15
|
+
const parseArguments = (args) => {
|
|
16
|
+
const options = { files: false, openapiMode: 'none' };
|
|
17
|
+
let configPath;
|
|
18
|
+
args.forEach((argument) => {
|
|
19
|
+
if (argument === '--files') {
|
|
20
|
+
options.files = true;
|
|
21
|
+
}
|
|
22
|
+
else if (argument === '--openapi') {
|
|
23
|
+
if (options.openapiMode !== 'none') {
|
|
24
|
+
throw new Error('Параметры --openapi и --openapi-only нельзя использовать одновременно');
|
|
25
|
+
}
|
|
26
|
+
options.openapiMode = 'generate';
|
|
27
|
+
}
|
|
28
|
+
else if (argument === '--openapi-only') {
|
|
29
|
+
if (options.openapiMode !== 'none') {
|
|
30
|
+
throw new Error('Параметры --openapi и --openapi-only нельзя использовать одновременно');
|
|
31
|
+
}
|
|
32
|
+
options.openapiMode = 'only';
|
|
33
|
+
}
|
|
34
|
+
else if (argument.startsWith('-')) {
|
|
35
|
+
throw new Error(`Неизвестный параметр: ${argument}`);
|
|
36
|
+
}
|
|
37
|
+
else if (configPath == null) {
|
|
38
|
+
configPath = argument;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
throw new Error('Можно указать только один файл конфигурации');
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
if (configPath == null) {
|
|
45
|
+
throw new Error('Укажите путь к файлу конфигурации');
|
|
46
|
+
}
|
|
47
|
+
return { configPath, ...options };
|
|
48
|
+
};
|
|
49
|
+
const validateModeConfig = (config, { files, openapiMode }) => {
|
|
50
|
+
if (openapiMode !== 'none' && config.openapi.path == null) {
|
|
51
|
+
throw new Error(`Для --openapi${openapiMode === 'only' ? '-only' : ''} укажите ключ config.openapi.path`);
|
|
52
|
+
}
|
|
53
|
+
if (files && config.files == null) {
|
|
54
|
+
throw new Error('Для --files укажите секцию config.files');
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
export async function runCli(args = process.argv.slice(2), services = { createServer }) {
|
|
58
|
+
if (args.includes('--help')) {
|
|
59
|
+
process.stdout.write(`${HELP_TEXT}\n`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const { configPath, files, openapiMode } = parseArguments(args);
|
|
63
|
+
const config = await readServerConfig(configPath);
|
|
64
|
+
const host = config.server.host ?? process.env.HOST ?? DEFAULT_HOST;
|
|
65
|
+
const port = config.server.port ?? Number(process.env.PORT ?? DEFAULT_PORT);
|
|
66
|
+
validateModeConfig(config, { files, openapiMode });
|
|
67
|
+
const runtimeConfig = { ...config, server: { ...config.server, host, port } };
|
|
68
|
+
const serverFacade = await services.createServer(runtimeConfig, { files });
|
|
69
|
+
if (openapiMode !== 'none') {
|
|
70
|
+
await serverFacade.openapi();
|
|
71
|
+
process.stdout.write(`OpenAPI-схема сохранена в ${config.openapi.path}\n`);
|
|
72
|
+
}
|
|
73
|
+
if (openapiMode === 'only') {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const fastify = serverFacade.fastify();
|
|
77
|
+
await fastify.listen();
|
|
78
|
+
fastify.log.info({ database: 'path' in config.database ? config.database.path : 'memory' }, 'Deep JSON Server запущен');
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { FastifyServerOptions } from 'fastify';
|
|
2
|
+
import type { DatabaseData, JsonObject } from './types.js';
|
|
3
|
+
export type DatabaseSchema = JsonObject;
|
|
4
|
+
export type DatabaseConfig = {
|
|
5
|
+
data: DatabaseData;
|
|
6
|
+
path?: never;
|
|
7
|
+
schema?: DatabaseSchema | string;
|
|
8
|
+
} | {
|
|
9
|
+
data?: never;
|
|
10
|
+
path: string;
|
|
11
|
+
schema?: DatabaseSchema | string;
|
|
12
|
+
};
|
|
13
|
+
export interface MemoryFile {
|
|
14
|
+
content: Uint8Array;
|
|
15
|
+
directory?: string;
|
|
16
|
+
mimeType: string;
|
|
17
|
+
name: string;
|
|
18
|
+
}
|
|
19
|
+
export type FilesConfig = {
|
|
20
|
+
data: MemoryFile[];
|
|
21
|
+
directory?: never;
|
|
22
|
+
metadata?: never;
|
|
23
|
+
} | {
|
|
24
|
+
data?: never;
|
|
25
|
+
directory: string;
|
|
26
|
+
metadata: string;
|
|
27
|
+
};
|
|
28
|
+
export interface OpenapiConfig {
|
|
29
|
+
path?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface ServerConfig {
|
|
32
|
+
cors?: boolean;
|
|
33
|
+
host?: string;
|
|
34
|
+
logger?: FastifyServerOptions['logger'];
|
|
35
|
+
maxFileSize?: number;
|
|
36
|
+
maxPageSize?: number;
|
|
37
|
+
port?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface DeepJsonServerConfig {
|
|
40
|
+
database: DatabaseConfig;
|
|
41
|
+
files?: FilesConfig;
|
|
42
|
+
openapi?: OpenapiConfig;
|
|
43
|
+
server?: ServerConfig;
|
|
44
|
+
}
|
|
45
|
+
export interface NormalizedServerConfig {
|
|
46
|
+
database: DatabaseConfig;
|
|
47
|
+
files?: FilesConfig;
|
|
48
|
+
openapi: OpenapiConfig;
|
|
49
|
+
server: ServerConfig;
|
|
50
|
+
}
|
|
51
|
+
/** Validates configuration and resolves relative paths. */
|
|
52
|
+
export declare const normalizeServerConfig: (config: DeepJsonServerConfig, directoryPath?: string) => NormalizedServerConfig;
|
|
53
|
+
/** Loads an ES module config and resolves paths from its directory. */
|
|
54
|
+
export declare function readServerConfig(configPath: string): Promise<NormalizedServerConfig>;
|