prisma-generator-express 1.18.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +399 -194
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/client/encodeQueryParams.d.ts +1 -0
- package/dist/client/encodeQueryParams.js +33 -0
- package/dist/client/encodeQueryParams.js.map +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/copy/misc.d.ts +5 -0
- package/dist/copy/misc.js +52 -0
- package/dist/copy/misc.js.map +1 -0
- package/dist/generators/generateImportPrismaStatement.d.ts +3 -0
- package/dist/generators/generateImportPrismaStatement.js +55 -0
- package/dist/generators/generateImportPrismaStatement.js.map +1 -0
- package/dist/generators/generateQueryBuilderHelper.d.ts +2 -0
- package/dist/generators/generateQueryBuilderHelper.js +139 -0
- package/dist/generators/generateQueryBuilderHelper.js.map +1 -0
- package/dist/generators/generateRouter.d.ts +6 -0
- package/dist/generators/generateRouter.js +340 -0
- package/dist/generators/generateRouter.js.map +1 -0
- package/dist/generators/generateUnifiedDocs.d.ts +1 -0
- package/dist/generators/generateUnifiedDocs.js +171 -0
- package/dist/generators/generateUnifiedDocs.js.map +1 -0
- package/dist/generators/generateUnifiedHandler.d.ts +6 -0
- package/dist/generators/generateUnifiedHandler.js +444 -0
- package/dist/generators/generateUnifiedHandler.js.map +1 -0
- package/dist/generators/generateUnifiedScalarUI.d.ts +5 -0
- package/dist/generators/generateUnifiedScalarUI.js +1390 -0
- package/dist/generators/generateUnifiedScalarUI.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/copyFiles.d.ts +6 -0
- package/dist/utils/copyFiles.js +123 -21
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/strings.d.ts +2 -0
- package/dist/utils/writeFileSafely.d.ts +10 -0
- package/dist/utils/writeFileSafely.js +86 -14
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +64 -31
- package/src/client/encodeQueryParams.ts +56 -0
- package/src/copy/buildModelOpenApi.ts +1569 -0
- package/src/copy/misc.ts +21 -0
- package/src/copy/operationDefinitions.ts +96 -0
- package/src/copy/parseQueryParams.ts +36 -21
- package/src/copy/routeConfig.ts +68 -28
- package/dist/generator.js +0 -47
- package/dist/generator.js.map +0 -1
- package/dist/helpers/generateImportPrismaStatement.js +0 -25
- package/dist/helpers/generateImportPrismaStatement.js.map +0 -1
- package/dist/helpers/generateOperation.js +0 -471
- package/dist/helpers/generateOperation.js.map +0 -1
- package/dist/helpers/generateRouteFile.js +0 -210
- package/dist/helpers/generateRouteFile.js.map +0 -1
- package/dist/utils/formatFile.js +0 -26
- package/dist/utils/formatFile.js.map +0 -1
- package/src/bin.ts +0 -2
- package/src/constants.ts +0 -1
- package/src/copy/encodeQueryParams.spec.ts +0 -303
- package/src/copy/encodeQueryParams.ts +0 -44
- package/src/copy/misc.spec.ts +0 -62
- package/src/copy/parseQueryParams.spec.ts +0 -187
- package/src/copy/transformZod.spec.ts +0 -763
- package/src/generator.ts +0 -54
- package/src/helpers/generateImportPrismaStatement.ts +0 -38
- package/src/helpers/generateOperation.ts +0 -515
- package/src/helpers/generateRouteFile.ts +0 -213
- package/src/utils/copyFiles.ts +0 -27
- package/src/utils/formatFile.ts +0 -22
- package/src/utils/strings.ts +0 -7
- package/src/utils/writeFileSafely.ts +0 -29
package/README.md
CHANGED
|
@@ -2,292 +2,497 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/js/prisma-generator-express)
|
|
4
4
|
[](https://www.npmjs.com/package/prisma-generator-express)
|
|
5
|
-
[](https://codecov.io/github/multipliedtwice/prisma-generator-express)
|
|
5
|
+
[](https://codecov.io/gh/multipliedtwice/prisma-generator-express)
|
|
7
6
|
[](LICENSE)
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
Prisma generator that creates Express CRUD API routes with OpenAPI documentation from your Prisma schema.
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
Running `npx prisma generate` produces:
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
- Handler functions for all Prisma operations (findMany, create, update, delete, etc.)
|
|
13
|
+
- Router generator with middleware support (before/after hooks per operation)
|
|
14
|
+
- OpenAPI 3.1 spec (JSON and YAML endpoints registered automatically per router)
|
|
15
|
+
- Documentation helpers for contract view and Scalar UI (require manual mounting)
|
|
16
|
+
- Client-side query parameter encoder
|
|
17
|
+
- Guard/variant shape enforcement via prisma-guard integration
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
- Create a router generator function that lets you select which routes to enable in your express app and which middlewares to apply.
|
|
19
|
+
## Compatibility
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
### Prisma version
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
- [Basic Usage](#basic-usage)
|
|
22
|
-
- [Router Generator Usage](#router-generator-usage)
|
|
23
|
-
- [Request Object Properties](#request-object-properties)
|
|
24
|
-
- [Router Schema](#router-schema)
|
|
23
|
+
Minimum supported Prisma version: **6.0.0**
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
Some operations require newer versions:
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
| Operation | Minimum Prisma version | Notes |
|
|
28
|
+
| --------------------- | ---------------------- | ------------------------------------ |
|
|
29
|
+
| `omit` parameter | 6.2.0 | Returns 400 on versions 6.0.x–6.1.x |
|
|
30
|
+
| `updateManyAndReturn` | 6.2.0 | PostgreSQL, CockroachDB, SQLite only |
|
|
29
31
|
|
|
32
|
+
### Database provider support
|
|
33
|
+
|
|
34
|
+
Most operations work across all Prisma-supported providers. Exceptions:
|
|
35
|
+
|
|
36
|
+
| Feature | PostgreSQL | CockroachDB | MySQL | SQLite | SQL Server | MongoDB |
|
|
37
|
+
| --------------------- | ---------- | ----------- | ----- | ------ | ---------- | ------- |
|
|
38
|
+
| `createManyAndReturn` | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ |
|
|
39
|
+
| `updateManyAndReturn` | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ |
|
|
40
|
+
| `skipDuplicates` | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
|
|
41
|
+
|
|
42
|
+
Operations not supported by your database provider return `501 Not Implemented` at runtime. The generator emits handlers for all operations regardless of provider — use selective route configuration to expose only supported operations.
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
30
45
|
```bash
|
|
31
|
-
|
|
46
|
+
npm install -D prisma-generator-express
|
|
32
47
|
```
|
|
33
48
|
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
Peer dependencies:
|
|
36
50
|
```bash
|
|
37
|
-
|
|
51
|
+
npm install @prisma/client express
|
|
38
52
|
```
|
|
39
53
|
|
|
40
|
-
|
|
54
|
+
Optional peer dependencies:
|
|
55
|
+
```bash
|
|
56
|
+
npm install prisma-sql # SQL optimization
|
|
57
|
+
npm install prisma-guard # Guard shape enforcement
|
|
58
|
+
npm install prisma-query-builder-ui # Visual query playground
|
|
59
|
+
```
|
|
41
60
|
|
|
42
|
-
|
|
61
|
+
## Setup
|
|
43
62
|
|
|
63
|
+
Add the generator to your `schema.prisma`:
|
|
44
64
|
```prisma
|
|
65
|
+
generator client {
|
|
66
|
+
provider = "prisma-client-js"
|
|
67
|
+
}
|
|
68
|
+
|
|
45
69
|
generator express {
|
|
46
70
|
provider = "prisma-generator-express"
|
|
47
71
|
}
|
|
48
72
|
```
|
|
49
73
|
|
|
50
|
-
|
|
74
|
+
The generator detects the Prisma client generator automatically. All standard provider values are supported: `prisma-client-js`, `@prisma/client`, and `prisma-client`.
|
|
51
75
|
|
|
76
|
+
Generate:
|
|
52
77
|
```bash
|
|
53
|
-
|
|
78
|
+
npx prisma generate
|
|
54
79
|
```
|
|
55
80
|
|
|
56
|
-
|
|
57
|
-
|
|
81
|
+
## Usage
|
|
58
82
|
```ts
|
|
59
|
-
import { PrismaClient } from '@prisma/client'
|
|
60
83
|
import express from 'express'
|
|
84
|
+
import { PrismaClient } from '@prisma/client'
|
|
85
|
+
import { UserRouter } from './generated/User/UserRouter'
|
|
61
86
|
|
|
62
87
|
const prisma = new PrismaClient()
|
|
63
88
|
const app = express()
|
|
64
89
|
|
|
65
|
-
app.use(express.json()) // for parsing application/json
|
|
66
|
-
|
|
67
|
-
// Attach Prisma to every request
|
|
68
90
|
app.use((req, res, next) => {
|
|
69
91
|
req.prisma = prisma
|
|
70
92
|
next()
|
|
71
93
|
})
|
|
72
|
-
```
|
|
73
94
|
|
|
74
|
-
|
|
95
|
+
const userConfig = {
|
|
96
|
+
enableAll: true,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
app.use('/', UserRouter(userConfig))
|
|
100
|
+
|
|
101
|
+
app.listen(3000, () => {
|
|
102
|
+
console.log('Server is running on http://localhost:3000')
|
|
103
|
+
})
|
|
104
|
+
```
|
|
75
105
|
|
|
106
|
+
## Selective routes with middleware
|
|
76
107
|
```ts
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
req.query = schema.parse(req.query)
|
|
86
|
-
next()
|
|
87
|
-
} catch (error) {
|
|
88
|
-
res.status(400).json({
|
|
89
|
-
error: 'Input Validation failed',
|
|
90
|
-
details: error.errors,
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
}
|
|
108
|
+
const userConfig = {
|
|
109
|
+
findMany: {
|
|
110
|
+
before: [authMiddleware],
|
|
111
|
+
},
|
|
112
|
+
create: {
|
|
113
|
+
before: [authMiddleware, validateBody],
|
|
114
|
+
},
|
|
115
|
+
findUnique: {},
|
|
94
116
|
}
|
|
95
117
|
|
|
96
|
-
app.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
app.use('/', UserRouter(userConfig))
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Only operations listed in the config (or all when `enableAll: true`) are registered. Operations not listed produce no routes.
|
|
122
|
+
|
|
123
|
+
## Guard shapes (variant-based field access)
|
|
124
|
+
|
|
125
|
+
Guard shapes require the `prisma-guard` package for runtime enforcement.
|
|
126
|
+
|
|
127
|
+
### Setup
|
|
128
|
+
```bash
|
|
129
|
+
npm install prisma-guard
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Extend your PrismaClient with the guard extension:
|
|
133
|
+
```ts
|
|
134
|
+
import { PrismaClient } from '@prisma/client'
|
|
135
|
+
import { guardExtension } from 'prisma-guard'
|
|
136
|
+
|
|
137
|
+
const prisma = new PrismaClient().$extends(guardExtension())
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Configuration
|
|
141
|
+
```ts
|
|
142
|
+
const userConfig = {
|
|
143
|
+
findMany: {
|
|
144
|
+
shape: {
|
|
145
|
+
admin: { select: { id: true, email: true, role: true } },
|
|
146
|
+
public: { select: { id: true, email: true } },
|
|
147
|
+
},
|
|
105
148
|
},
|
|
106
|
-
|
|
149
|
+
guard: {
|
|
150
|
+
variantHeader: 'x-api-variant',
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
app.use('/', UserRouter(userConfig))
|
|
107
155
|
```
|
|
108
156
|
|
|
109
|
-
|
|
157
|
+
When a guard shape is configured on an operation, the variant is resolved from the configured header (default: `x-api-variant`) or a custom `resolveVariant` function. The resolved variant selects which shape config to apply. If prisma-guard is not installed or the client is not extended with the guard extension, requests to guarded routes return 500 with an actionable error message.
|
|
158
|
+
|
|
159
|
+
## Request body format
|
|
160
|
+
|
|
161
|
+
All write operations accept the full Prisma args object as the JSON request body. The body must be a JSON object — sending `null`, arrays, or other non-object values returns 400.
|
|
162
|
+
```ts
|
|
163
|
+
// Create
|
|
164
|
+
{ "data": { "name": "Alice", "email": "alice@example.com" }, "select": { "id": true } }
|
|
165
|
+
|
|
166
|
+
// Update
|
|
167
|
+
{ "where": { "id": 1 }, "data": { "name": "Bob" } }
|
|
168
|
+
|
|
169
|
+
// Delete
|
|
170
|
+
{ "where": { "id": 1 } }
|
|
171
|
+
|
|
172
|
+
// Upsert
|
|
173
|
+
{ "where": { "id": 1 }, "create": { "name": "Alice" }, "update": { "name": "Bob" } }
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Write operations that return records (create, update, delete, upsert, createManyAndReturn, updateManyAndReturn) support `select`, `include`, and `omit` in the request body to control the response shape.
|
|
177
|
+
|
|
178
|
+
### Bulk operations
|
|
110
179
|
|
|
111
|
-
|
|
180
|
+
`createMany`, `createManyAndReturn`, `updateMany`, and `updateManyAndReturn` accept scalar-only data inputs. Nested relation writes are not supported in bulk operations.
|
|
112
181
|
|
|
113
|
-
|
|
182
|
+
### Batch operation safety
|
|
114
183
|
|
|
184
|
+
`deleteMany`, `updateMany`, and `updateManyAndReturn` require a `where` field in the request body. Requests without `where` are rejected with 400 to prevent accidental mass operations. Sending `{ "where": {} }` is valid and matches all records — this protection catches accidental omission, not intentional broad operations.
|
|
185
|
+
|
|
186
|
+
## Query encoding (client side)
|
|
115
187
|
```ts
|
|
116
|
-
import
|
|
117
|
-
import type { Response, Request, NextFunction, RequestHandler } from 'express'
|
|
188
|
+
import { encodeQueryParams } from './generated/client/encodeQueryParams'
|
|
118
189
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
190
|
+
const params = encodeQueryParams({
|
|
191
|
+
where: { status: 'active', role: { in: ['admin', 'editor'] } },
|
|
192
|
+
select: { id: true, email: true },
|
|
193
|
+
take: 20,
|
|
194
|
+
})
|
|
123
195
|
|
|
124
|
-
const
|
|
196
|
+
const response = await fetch(`/user?${params}`)
|
|
197
|
+
```
|
|
125
198
|
|
|
126
|
-
|
|
199
|
+
Complex values (`where`, `select`, `include`, `omit`, `orderBy`) are JSON-stringified. Primitives (`take`, `skip`) are sent directly. The encoder handles BigInt serialization automatically.
|
|
127
200
|
|
|
128
|
-
|
|
129
|
-
* Middleware to attach Prisma client instance to the request object.
|
|
130
|
-
* This ensures that Prisma client is available in all subsequent middleware and route handlers.
|
|
131
|
-
*/
|
|
132
|
-
const addPrisma: RequestHandler = (
|
|
133
|
-
req: Request,
|
|
134
|
-
res: Response,
|
|
135
|
-
next: NextFunction,
|
|
136
|
-
) => {
|
|
137
|
-
req.prisma = prisma
|
|
138
|
-
next()
|
|
139
|
-
}
|
|
201
|
+
## Response shaping: select, include, omit
|
|
140
202
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
203
|
+
Read and single-record write operations support three response shaping parameters:
|
|
204
|
+
|
|
205
|
+
- **`select`** — choose which fields to include. Set scalar fields to `true`, use nested objects for relations.
|
|
206
|
+
- **`include`** — include relations in addition to all scalar fields. Use nested `include`/`select` for deep loading.
|
|
207
|
+
- **`omit`** — exclude specific scalar fields from the response.
|
|
208
|
+
|
|
209
|
+
`select` and `include` cannot be used together at the same level. `select` and `omit` cannot be used together at the same level. `omit` can be combined with `include`.
|
|
210
|
+
|
|
211
|
+
The `omit` parameter requires Prisma 6.2.0+. On versions 6.0.x–6.1.x, requests using `omit` return 400.
|
|
212
|
+
|
|
213
|
+
## BigInt and Decimal handling
|
|
214
|
+
|
|
215
|
+
BigInt and Decimal values are serialized as strings in JSON responses. Buffer and Uint8Array values are serialized as base64 strings. The OpenAPI spec documents BigInt and Decimal fields as `type: string`.
|
|
216
|
+
|
|
217
|
+
On the client side, `encodeQueryParams` handles BigInt serialization automatically.
|
|
218
|
+
|
|
219
|
+
## Pagination
|
|
220
|
+
|
|
221
|
+
`findManyPaginated` returns `{ data, total, hasMore }`. When the runtime supports interactive transactions, the count and query execute in a transaction for consistency. On runtimes without interactive transaction support, the queries run independently with eventual consistency on the `total` count.
|
|
222
|
+
|
|
223
|
+
The `hasMore` field is reliable for forward offset pagination (`skip` + `take`) only. When using cursor-based pagination or negative `take` (backward pagination), `hasMore` may be inaccurate.
|
|
224
|
+
|
|
225
|
+
Configure default and maximum page sizes:
|
|
226
|
+
```ts
|
|
227
|
+
UserRouter({
|
|
228
|
+
findManyPaginated: {},
|
|
229
|
+
pagination: {
|
|
230
|
+
defaultLimit: 20,
|
|
231
|
+
maxLimit: 100,
|
|
232
|
+
},
|
|
233
|
+
})
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
`pagination.defaultLimit` is applied when the client omits `take`. `pagination.maxLimit` caps `take` by absolute value. Both settings apply to `findMany` and `findManyPaginated`.
|
|
237
|
+
|
|
238
|
+
## Error handling
|
|
239
|
+
|
|
240
|
+
All errors are returned as JSON with a `message` field:
|
|
241
|
+
```json
|
|
242
|
+
{ "message": "Unique constraint violation" }
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Each generated router installs an error-handling middleware that normalizes errors. Prisma error codes are mapped to appropriate HTTP status codes. Guard errors are mapped as follows: `ShapeError` and `CallerError` → 400, `PolicyError` → 403.
|
|
246
|
+
|
|
247
|
+
| Status | Description |
|
|
248
|
+
| ------ | ------------------------------------------ |
|
|
249
|
+
| 400 | Invalid parameters, body, or query |
|
|
250
|
+
| 403 | Guard policy rejected |
|
|
251
|
+
| 404 | Record not found |
|
|
252
|
+
| 409 | Unique constraint or transaction conflict |
|
|
253
|
+
| 500 | Internal server error |
|
|
254
|
+
| 501 | Feature not supported by database provider |
|
|
255
|
+
| 503 | Database connection pool timeout |
|
|
256
|
+
|
|
257
|
+
## Security
|
|
258
|
+
|
|
259
|
+
All incoming JSON bodies and query parameters are sanitized to reject `__proto__`, `constructor`, and `prototype` keys, preventing prototype pollution attacks.
|
|
260
|
+
|
|
261
|
+
## Documentation endpoints
|
|
262
|
+
|
|
263
|
+
### Automatic (registered by each router)
|
|
264
|
+
|
|
265
|
+
Each router automatically registers OpenAPI spec endpoints when not in production:
|
|
266
|
+
|
|
267
|
+
| Endpoint | Description |
|
|
268
|
+
| ----------------------- | --------------------- |
|
|
269
|
+
| `/{model}/openapi.json` | OpenAPI 3.1 JSON spec |
|
|
270
|
+
| `/{model}/openapi.yaml` | OpenAPI 3.1 YAML spec |
|
|
271
|
+
|
|
272
|
+
Actual paths depend on `customUrlPrefix` and `addModelPrefix` configuration.
|
|
273
|
+
|
|
274
|
+
### Manual (generated helpers, require mounting)
|
|
275
|
+
|
|
276
|
+
The generator produces helper functions that you mount yourself. Pass the same config object used for the router to keep docs and runtime in sync:
|
|
277
|
+
```ts
|
|
278
|
+
import {
|
|
279
|
+
generateCombinedDocs,
|
|
280
|
+
registerModelDocs,
|
|
281
|
+
} from './generated/combinedDocs'
|
|
282
|
+
|
|
283
|
+
const userConfig = {
|
|
284
|
+
findMany: { before: [authMiddleware] },
|
|
285
|
+
create: {},
|
|
286
|
+
findUnique: {},
|
|
151
287
|
}
|
|
152
288
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
* will be available in req.locals?.data for modifications
|
|
156
|
-
*/
|
|
157
|
-
const afterFindFirst: RequestHandler = (
|
|
158
|
-
req: Request,
|
|
159
|
-
res: Response,
|
|
160
|
-
next: NextFunction,
|
|
161
|
-
) => {
|
|
162
|
-
console.log('req.locals?.data :>> ', req.locals?.data)
|
|
163
|
-
next()
|
|
289
|
+
const postConfig = {
|
|
290
|
+
enableAll: true,
|
|
164
291
|
}
|
|
165
292
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
allow: [
|
|
182
|
-
'select.id',
|
|
183
|
-
'select.full_name',
|
|
184
|
-
'select.emailAddress',
|
|
185
|
-
'select.orders[].ProductName',
|
|
186
|
-
'select.orders[].quantity',
|
|
187
|
-
'where.id',
|
|
188
|
-
'where.createdAt',
|
|
189
|
-
],
|
|
293
|
+
app.use('/', UserRouter(userConfig))
|
|
294
|
+
app.use('/', PostRouter(postConfig))
|
|
295
|
+
|
|
296
|
+
registerModelDocs(app, '/docs', {
|
|
297
|
+
User: userConfig,
|
|
298
|
+
Post: postConfig,
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
app.get(
|
|
302
|
+
'/docs',
|
|
303
|
+
generateCombinedDocs({
|
|
304
|
+
title: 'My API',
|
|
305
|
+
modelConfigs: {
|
|
306
|
+
User: userConfig,
|
|
307
|
+
Post: postConfig,
|
|
190
308
|
},
|
|
191
|
-
},
|
|
192
|
-
|
|
309
|
+
}),
|
|
310
|
+
)
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
| Endpoint | Description |
|
|
314
|
+
| ----------------------------- | ----------------------- |
|
|
315
|
+
| `/docs` | Combined index page |
|
|
316
|
+
| `/docs/{model}` | Contract view (default) |
|
|
317
|
+
| `/docs/{model}?ui=scalar` | Scalar interactive UI |
|
|
318
|
+
| `/docs/{model}?ui=json` | Raw JSON |
|
|
319
|
+
| `/docs/{model}?ui=yaml` | Raw YAML |
|
|
320
|
+
| `/docs/{model}?ui=playground` | Query playground |
|
|
321
|
+
|
|
322
|
+
Disable in production via `NODE_ENV=production` or `DISABLE_OPENAPI=true`. Override with `disableOpenApi: false` in config to force-enable.
|
|
323
|
+
|
|
324
|
+
### Spec paths and mount prefixes
|
|
325
|
+
|
|
326
|
+
Use `specBasePath` to set the base path for OpenAPI spec and docs independently of route registration:
|
|
327
|
+
```ts
|
|
328
|
+
const userConfig = {
|
|
193
329
|
enableAll: true,
|
|
194
|
-
|
|
330
|
+
specBasePath: '/api',
|
|
195
331
|
}
|
|
196
332
|
|
|
197
|
-
app.use(
|
|
198
|
-
|
|
333
|
+
app.use('/api', UserRouter(userConfig))
|
|
334
|
+
```
|
|
199
335
|
|
|
200
|
-
|
|
201
|
-
|
|
336
|
+
When `specBasePath` is not set, `customUrlPrefix` is used for both runtime routes and spec paths.
|
|
337
|
+
|
|
338
|
+
## prisma-sql integration
|
|
339
|
+
|
|
340
|
+
When `prisma-sql` is installed, the generated handlers automatically attempt to use its `speedExtension` for optimized SQL execution. The extension activates only when a database connector is provided on the request object.
|
|
341
|
+
|
|
342
|
+
Set `req.postgres` or `req.sqlite` in your middleware to activate the extension:
|
|
343
|
+
```ts
|
|
344
|
+
import { PrismaClient } from '@prisma/client'
|
|
345
|
+
import postgres from 'postgres'
|
|
346
|
+
|
|
347
|
+
const prisma = new PrismaClient()
|
|
348
|
+
const sql = postgres(process.env.DATABASE_URL!)
|
|
349
|
+
|
|
350
|
+
app.use((req, res, next) => {
|
|
351
|
+
req.prisma = prisma
|
|
352
|
+
req.postgres = sql
|
|
353
|
+
next()
|
|
202
354
|
})
|
|
203
355
|
```
|
|
204
356
|
|
|
205
|
-
|
|
357
|
+
Without a connector on the request, the handlers use the standard PrismaClient. Set `DEBUG=true` in the environment to enable prisma-sql debug logging.
|
|
358
|
+
|
|
359
|
+
## Query parameter parsing
|
|
206
360
|
|
|
207
|
-
The
|
|
361
|
+
GET query values are parsed server-side. Strings starting with `{`, `[`, or `"` are JSON-parsed. The strings `true`, `false`, `null` are converted to their JS equivalents. Numeric conversion only applies to `take` and `skip`. Use `encodeQueryParams` on the client side to avoid encoding issues.
|
|
208
362
|
|
|
209
|
-
|
|
210
|
-
| ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
211
|
-
| `prisma` | PrismaClient | An instance of PrismaClient that allows the middleware to interact with your database. |
|
|
212
|
-
| `passToNext` | boolean | Optional, if `true` - the result of a Prisma request will be passed to the next middleware as `if (req.locals) req.locals.data` |
|
|
213
|
-
| `outputValidation` | ZodType | (Optional) A Zod schema used to validate the data returned from the Prisma query before sending it to the client. |
|
|
363
|
+
## Router schema
|
|
214
364
|
|
|
215
|
-
|
|
365
|
+
| Operation | Method | Path |
|
|
366
|
+
| ------------------- | ------ | ---------------- |
|
|
367
|
+
| findMany | GET | `/` |
|
|
368
|
+
| findFirst | GET | `/first` |
|
|
369
|
+
| findFirstOrThrow | GET | `/first/strict` |
|
|
370
|
+
| findUnique | GET | `/unique` |
|
|
371
|
+
| findUniqueOrThrow | GET | `/unique/strict` |
|
|
372
|
+
| findManyPaginated | GET | `/paginated` |
|
|
373
|
+
| count | GET | `/count` |
|
|
374
|
+
| aggregate | GET | `/aggregate` |
|
|
375
|
+
| groupBy | GET | `/groupby` |
|
|
376
|
+
| create | POST | `/` |
|
|
377
|
+
| createMany | POST | `/many` |
|
|
378
|
+
| createManyAndReturn | POST | `/many/return` |
|
|
379
|
+
| update | PUT | `/` |
|
|
380
|
+
| updateMany | PUT | `/many` |
|
|
381
|
+
| updateManyAndReturn | PUT | `/many/return` |
|
|
382
|
+
| upsert | PATCH | `/` |
|
|
383
|
+
| delete | DELETE | `/` |
|
|
384
|
+
| deleteMany | DELETE | `/many` |
|
|
216
385
|
|
|
217
|
-
|
|
218
|
-
| ------------ | -------- | ------------ |
|
|
219
|
-
| `findUnique` | `GET` | `/:id` |
|
|
220
|
-
| `findFirst` | `GET` | `/first` |
|
|
221
|
-
| `findMany` | `GET` | `/` |
|
|
222
|
-
| `aggregate` | `GET` | `/aggregate` |
|
|
223
|
-
| `count` | `GET` | `/count` |
|
|
224
|
-
| `groupBy` | `GET` | `/groupby` |
|
|
225
|
-
| `create` | `POST` | `/` |
|
|
226
|
-
| `createMany` | `POST` | `/many` |
|
|
227
|
-
| `update` | `PUT` | `/` |
|
|
228
|
-
| `updateMany` | `PUT` | `/many` |
|
|
229
|
-
| `upsert` | `PATCH` | `/` |
|
|
230
|
-
| `delete` | `DELETE` | `/` |
|
|
231
|
-
| `deleteMany` | `DELETE` | `/many` |
|
|
386
|
+
Paths shown are relative suffixes. Actual paths include the model prefix (e.g., `/user/first`) unless `addModelPrefix: false`, and any `customUrlPrefix`.
|
|
232
387
|
|
|
233
|
-
##
|
|
388
|
+
## Skipping models
|
|
234
389
|
|
|
390
|
+
Add `/// generator off` to a model's documentation to skip generation:
|
|
235
391
|
```prisma
|
|
236
392
|
/// generator off
|
|
237
|
-
model
|
|
238
|
-
|
|
239
|
-
full_name String
|
|
240
|
-
emailAddress String @unique
|
|
241
|
-
createdAt DateTime @default(now())
|
|
242
|
-
orders orderItem[]
|
|
393
|
+
model InternalLog {
|
|
394
|
+
id Int @id
|
|
243
395
|
}
|
|
244
396
|
```
|
|
245
397
|
|
|
246
|
-
##
|
|
398
|
+
## Configuration
|
|
399
|
+
```ts
|
|
400
|
+
interface RouteConfig {
|
|
401
|
+
enableAll?: boolean
|
|
402
|
+
addModelPrefix?: boolean // default: true
|
|
403
|
+
customUrlPrefix?: string
|
|
404
|
+
specBasePath?: string
|
|
405
|
+
disableOpenApi?: boolean
|
|
406
|
+
scalarCdnUrl?: string
|
|
407
|
+
|
|
408
|
+
openApiTitle?: string
|
|
409
|
+
openApiDescription?: string
|
|
410
|
+
openApiVersion?: string
|
|
411
|
+
openApiServers?: OpenApiServerConfig[]
|
|
412
|
+
openApiSecuritySchemes?: Record<string, OpenApiSecuritySchemeConfig>
|
|
413
|
+
openApiSecurity?: Record<string, string[]>[]
|
|
414
|
+
|
|
415
|
+
guard?: {
|
|
416
|
+
resolveVariant?: (req: Request) => string | undefined
|
|
417
|
+
variantHeader?: string // default: 'x-api-variant'
|
|
418
|
+
}
|
|
247
419
|
|
|
248
|
-
|
|
420
|
+
queryBuilder?: QueryBuilderConfig | false
|
|
249
421
|
|
|
250
|
-
|
|
422
|
+
pagination?: {
|
|
423
|
+
defaultLimit?: number
|
|
424
|
+
maxLimit?: number
|
|
425
|
+
}
|
|
251
426
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
427
|
+
// per-operation config
|
|
428
|
+
findMany?: OperationConfig
|
|
429
|
+
findUnique?: OperationConfig
|
|
430
|
+
findUniqueOrThrow?: OperationConfig
|
|
431
|
+
findFirst?: OperationConfig
|
|
432
|
+
findFirstOrThrow?: OperationConfig
|
|
433
|
+
findManyPaginated?: OperationConfig
|
|
434
|
+
create?: OperationConfig
|
|
435
|
+
createMany?: OperationConfig
|
|
436
|
+
createManyAndReturn?: OperationConfig
|
|
437
|
+
update?: OperationConfig
|
|
438
|
+
updateMany?: OperationConfig
|
|
439
|
+
updateManyAndReturn?: OperationConfig
|
|
440
|
+
upsert?: OperationConfig
|
|
441
|
+
delete?: OperationConfig
|
|
442
|
+
deleteMany?: OperationConfig
|
|
443
|
+
aggregate?: OperationConfig
|
|
444
|
+
count?: OperationConfig
|
|
445
|
+
groupBy?: OperationConfig
|
|
258
446
|
}
|
|
259
|
-
```
|
|
260
447
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
448
|
+
interface OperationConfig {
|
|
449
|
+
before?: RequestHandler[]
|
|
450
|
+
after?: RequestHandler[]
|
|
451
|
+
shape?: Record<string, any>
|
|
452
|
+
}
|
|
264
453
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
454
|
+
interface QueryBuilderConfig {
|
|
455
|
+
enabled?: boolean
|
|
456
|
+
port?: number
|
|
457
|
+
host?: string
|
|
458
|
+
schemaPath?: string
|
|
459
|
+
databaseUrl?: string
|
|
268
460
|
}
|
|
269
|
-
type Params = Record<string, RecursiveUrlParams | string>
|
|
270
461
|
```
|
|
271
462
|
|
|
272
|
-
|
|
463
|
+
`customUrlPrefix` is normalized to ensure a leading slash and strip trailing slashes.
|
|
464
|
+
|
|
465
|
+
`specBasePath` controls the base path used in OpenAPI spec paths and docs examples, independent of `customUrlPrefix`.
|
|
273
466
|
|
|
467
|
+
`openApiServers` sets the `servers` array in the OpenAPI spec:
|
|
274
468
|
```ts
|
|
275
|
-
|
|
469
|
+
UserRouter({
|
|
470
|
+
enableAll: true,
|
|
471
|
+
openApiServers: [
|
|
472
|
+
{ url: 'https://api.example.com/v1', description: 'Production' },
|
|
473
|
+
],
|
|
474
|
+
})
|
|
276
475
|
```
|
|
277
476
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
477
|
+
`openApiSecuritySchemes` and `openApiSecurity` set the security configuration in the OpenAPI spec:
|
|
478
|
+
```ts
|
|
479
|
+
UserRouter({
|
|
480
|
+
enableAll: true,
|
|
481
|
+
openApiSecuritySchemes: {
|
|
482
|
+
bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
|
|
483
|
+
},
|
|
484
|
+
openApiSecurity: [{ bearerAuth: [] }],
|
|
485
|
+
})
|
|
486
|
+
```
|
|
285
487
|
|
|
286
|
-
|
|
488
|
+
## Environment variables
|
|
287
489
|
|
|
288
|
-
|
|
490
|
+
| Variable | Default | Description |
|
|
491
|
+
| ----------------- | ------- | ----------------------------------- |
|
|
492
|
+
| `DISABLE_OPENAPI` | `false` | Disable OpenAPI endpoints |
|
|
493
|
+
| `NODE_ENV` | - | Set to `production` to disable docs |
|
|
494
|
+
| `DEBUG` | `false` | Enable prisma-sql debug logging |
|
|
289
495
|
|
|
290
|
-
|
|
291
|
-
- Super Kick Gym - [Brazilian Jiu Jitsu in Bangkok](https://en.bjj-bangkok.com)
|
|
496
|
+
## License
|
|
292
497
|
|
|
293
|
-
|
|
498
|
+
MIT
|