@alevnyacow/nzmt 0.16.16 β 0.16.18
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 +59 -84
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,34 +4,32 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Scaffold full-stack modules in Next.js in seconds with Next **Zod Modules Toolkit (NZMT)**.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Get **a DDD-inspired architecture with a contract-first approach** β and Server Actions working out of the box.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**API, services, stores, entities, validation, and React Query hooks β all generated for you.** No framework. No lock-in. Just production-ready Next.js.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
# π How it works
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
- initialize NZMT once
|
|
16
|
+
- run the scaffolder (e.g. `npx nzmt crud-api user`)
|
|
17
|
+
- tweak a few files
|
|
18
|
+
- get ready-to-use React Query hooks and a backend usable via Server Actions
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
- π§ Focus on your domain logic without drowning in full-blown DDD.
|
|
19
|
-
- β¨ DI, handy API controllers and a bunch of other cool things aimed at improving your DX out of the box.
|
|
20
|
-
- πͺ Services, controllers, client queries, and other programmer stuff appear at the snap of a finger.
|
|
21
|
-
|
|
22
|
-
# Quick start with Prisma
|
|
20
|
+
# π¬ Quick start with Prisma
|
|
23
21
|
|
|
24
22
|
Assuming you have a Next.js project with a generated Prisma client, and configured `@tanstack/react-query`:
|
|
25
23
|
|
|
26
|
-
## Setup
|
|
24
|
+
## βοΈ Setup
|
|
27
25
|
|
|
28
|
-
1. Install
|
|
26
|
+
### 1. Install
|
|
29
27
|
|
|
30
28
|
```bash
|
|
31
29
|
npm i inversify zod reflect-metadata @alevnyacow/nzmt
|
|
32
30
|
```
|
|
33
31
|
|
|
34
|
-
2. Enable decorators in tsconfig.json
|
|
32
|
+
### 2. Enable decorators in tsconfig.json
|
|
35
33
|
|
|
36
34
|
```ts
|
|
37
35
|
{
|
|
@@ -42,26 +40,25 @@ npm i inversify zod reflect-metadata @alevnyacow/nzmt
|
|
|
42
40
|
}
|
|
43
41
|
```
|
|
44
42
|
|
|
45
|
-
3. Initialize
|
|
43
|
+
### 3. Initialize
|
|
46
44
|
|
|
47
45
|
```bash
|
|
48
46
|
npx nzmt init prismaClientPath:@/generated/prisma/client
|
|
49
47
|
```
|
|
50
48
|
|
|
51
|
-
This command generates:
|
|
49
|
+
This command takes absolute path to your Prisma client as input and generates:
|
|
52
50
|
|
|
53
51
|
- `nzmt.config.json` file
|
|
54
|
-
- DI
|
|
55
|
-
-
|
|
56
|
-
- Some infrastructure helpers also already injected in DI
|
|
52
|
+
- DI setup
|
|
53
|
+
- infrastructure helpers
|
|
57
54
|
|
|
58
|
-
4.
|
|
55
|
+
### 4. Plug Prisma adapter
|
|
59
56
|
|
|
60
|
-
|
|
57
|
+
Edit scaffolded `/server/infrastructure/prisma/client.ts` file
|
|
61
58
|
|
|
62
|
-
|
|
59
|
+
## π Making full-stack CRUD for `User` entity with React queries and Server Actions
|
|
63
60
|
|
|
64
|
-
|
|
61
|
+
Assuming you have `User` prisma schema.
|
|
65
62
|
|
|
66
63
|
```bash
|
|
67
64
|
npx nzmt crud-api user
|
|
@@ -78,41 +75,37 @@ This command generates:
|
|
|
78
75
|
|
|
79
76
|
Everything is wired automatically via DI β no manual setup needed.
|
|
80
77
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
3. Tweak `UserStore` schemas if needed in scaffolded `/server/stores/users/user.store.ts` file.
|
|
78
|
+
Then tweak a few files:
|
|
84
79
|
|
|
85
|
-
|
|
80
|
+
- `/shared/entities/user/user.entity.ts` β entity schema
|
|
81
|
+
- `/server/stores/users/user.store.ts` β store schemas (if default schemas do not fit your needs)
|
|
82
|
+
- `/server/stores/users/user.store.prisma.ts` β map `UserStore` contracts to Prisma client contracts
|
|
86
83
|
|
|
87
|
-
|
|
84
|
+
π One command + few tweaks β ready-to-use React Query hooks & Server Actions backend.
|
|
88
85
|
|
|
89
|
-
|
|
86
|
+
## βοΈ Using scaffolded React query hooks
|
|
90
87
|
|
|
91
88
|
```
|
|
92
89
|
Schema: Client β React Query β API β Controller β Service β Store β DB
|
|
93
90
|
```
|
|
94
91
|
|
|
95
|
-
Everything is already scaffolded and grouped in handy namespace for you, just import it and use! β¨
|
|
96
|
-
|
|
97
|
-
Even invalidations are working out of the box (though you can modify scaffolded queries any way you want).
|
|
98
|
-
|
|
99
92
|
```tsx
|
|
100
93
|
'use client'
|
|
101
94
|
|
|
102
95
|
import { UserQueries } from "@/client/shared/queries/user";
|
|
103
96
|
|
|
104
|
-
export default function
|
|
97
|
+
export default function () {
|
|
105
98
|
const { mutate: addUser } = UserQueries.usePOST()
|
|
106
99
|
const { data, isFetching } = UserQueries.useGET({ query: {} })
|
|
107
100
|
|
|
108
|
-
const
|
|
109
|
-
addUser({ body: { payload: { name:
|
|
101
|
+
const addRandomUser = () => {
|
|
102
|
+
addUser({ body: { payload: { name: `${Math.random()}` } } })
|
|
110
103
|
}
|
|
111
104
|
|
|
112
105
|
return (
|
|
113
106
|
<div>
|
|
114
|
-
<button onClick={
|
|
115
|
-
|
|
107
|
+
<button onClick={addRandomUser}>
|
|
108
|
+
New random user
|
|
116
109
|
</button>
|
|
117
110
|
|
|
118
111
|
{isFetching ? 'Loading users...' : JSON.stringify(data)}
|
|
@@ -122,14 +115,12 @@ export default function Home() {
|
|
|
122
115
|
|
|
123
116
|
```
|
|
124
117
|
|
|
125
|
-
|
|
118
|
+
## πΌ Using scaffolded Service methods as Next server actions
|
|
126
119
|
|
|
127
120
|
```
|
|
128
121
|
Schema: Server Action β Service β Store β DB
|
|
129
122
|
```
|
|
130
123
|
|
|
131
|
-
Just get required instances from DI and use methods. That's all. β¨
|
|
132
|
-
|
|
133
124
|
```tsx
|
|
134
125
|
'use server'
|
|
135
126
|
|
|
@@ -144,71 +135,55 @@ export default async function() {
|
|
|
144
135
|
*/
|
|
145
136
|
const userService = fromDI<UserService>('UserService')
|
|
146
137
|
|
|
147
|
-
const
|
|
148
|
-
filter: { id: '
|
|
138
|
+
const user1 = await userService.getDetails({
|
|
139
|
+
filter: { id: 'user-1-id' }
|
|
149
140
|
})
|
|
150
141
|
|
|
151
|
-
return <div>
|
|
152
|
-
Take a break, {JSON.stringify(driver8)}
|
|
153
|
-
{JSON.stringify(driver8)}, take a break
|
|
154
|
-
</div>
|
|
142
|
+
return <div>{JSON.stringify(user1)}</div>
|
|
155
143
|
}
|
|
156
144
|
```
|
|
157
145
|
|
|
158
|
-
#
|
|
146
|
+
# β FAQ
|
|
159
147
|
|
|
160
|
-
##
|
|
148
|
+
## What does DDD-inspired mean?
|
|
149
|
+
|
|
150
|
+
NZMT puts your business domain first. Entities drive the architecture, so backend and frontend stay consistent, and all layers are generated from your entity contracts and schemas.
|
|
161
151
|
|
|
162
|
-
|
|
152
|
+
## What does contract-first mean?
|
|
163
153
|
|
|
164
|
-
|
|
154
|
+
The behavior of all server modules in NZMT is governed by Zod schemas. Function signatures and entity contracts are derived from these schemas. There is also automatic runtime validation to ensure that all data β function arguments and entity models β conform to their schemas.
|
|
165
155
|
|
|
166
|
-
|
|
156
|
+
## Can I tweak scaffolded files?
|
|
157
|
+
|
|
158
|
+
Yes β everything is fully editable, including configuration. Think of NZMT as a shadcn-style approach for full-stack: scaffold first, then fully own the code. Moreover, your changes are preserved on subsequent generations. For example, if you modify a generated query and regenerate later, your edits stay intact.
|
|
167
159
|
|
|
168
160
|
## Do I really need to understand DI and other fancy concepts to use NZMT?
|
|
169
161
|
|
|
170
|
-
No. NZMT
|
|
162
|
+
No. NZMT handles dependency injection (DI) for you using `inversifyjs`. You donβt need to set it up manually.
|
|
163
|
+
To get an instance of a service anywhere in your server code, just use:
|
|
171
164
|
|
|
172
165
|
```tsx
|
|
166
|
+
import { fromDI } from '@/server/di'
|
|
167
|
+
|
|
173
168
|
const userService = fromDI<UserService>('UserService')
|
|
174
169
|
```
|
|
175
170
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
Good design is impossible without precise terminology. The definition of a "Repository" can vary depending on the terminology used. Itβs frustrating when youβve spent your whole life writing repositories, and then some smart aleck comes along and accuses you of having been writing, say, Data Access Objects all this time! In general, a "Repository" is simply a pattern for working with data. Often, what we really need isnβt a specific pattern, but a properly separated abstraction layer for data handling, which we can then adapt to our needs. Thatβs exactly why the names of the modules used for the Data Layer in NZMT are kept as abstract as possible, without tying them to any specific data-handling pattern.
|
|
179
|
-
|
|
180
|
-
This approach wasnβt invented here; it has already proven successful, for example, in Go.
|
|
181
|
-
|
|
182
|
-
## Why not just use plain Next.js?
|
|
171
|
+
Here, `fromDI` is strongly typed β your IDE will give autocomplete automatically.
|
|
183
172
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
NZMT removes the repetitive parts:
|
|
187
|
-
- validation
|
|
188
|
-
- API wiring
|
|
189
|
-
- client queries
|
|
190
|
-
- service layer
|
|
191
|
-
- data layer
|
|
192
|
-
|
|
193
|
-
So you can focus on your logic while NZMT handles boring tech stuff like folder structure and contracts.
|
|
173
|
+
## Why data layer modules are called `Stores` and not `Repositories`?
|
|
194
174
|
|
|
195
|
-
|
|
175
|
+
A βRepositoryβ is a specific design pattern for managing data. NZMT prefers Stores β a simple, flexible abstraction for your data layer that can adapt to your needs regardless of the specific pattern. This approach helps to keep your code simple, and it has been successfully used in other languages, like Go.
|
|
196
176
|
|
|
197
177
|
## Why not use Nest or tRPC?
|
|
198
178
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
`NZMT` sits between `tRPC` and `NestJS`:
|
|
202
|
-
|
|
203
|
-
- from tRPC β type safety and DX
|
|
204
|
-
- from NestJS β structure and layering, but more DDD-inspired
|
|
179
|
+
`NZMT` combines the best of both worlds in one package while staying in plain Next.js:
|
|
205
180
|
|
|
206
|
-
|
|
207
|
-
-
|
|
208
|
-
- no magic runtime
|
|
209
|
-
- full control over your code
|
|
210
|
-
- power of react-query for client-server requests
|
|
211
|
-
- no new layers of client-server interaction
|
|
181
|
+
- From tRPC β type safety and developer experience
|
|
182
|
+
- From NestJS β structured architecture (but more DDD-inspired) with intuitive DI
|
|
212
183
|
|
|
213
|
-
|
|
184
|
+
Plus:
|
|
214
185
|
|
|
186
|
+
- No framework lock-in
|
|
187
|
+
- No magic runtime
|
|
188
|
+
- Full control over your code
|
|
189
|
+
- No extra client-server layers
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alevnyacow/nzmt",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.18",
|
|
4
4
|
"description": "Next Zod Modules Toolkit",
|
|
5
5
|
"keywords": ["next", "full-stack", "server", "backend", "cli", "scaffolder", "zod", "rest", "contract programming", "react-query", "ddd", "domain-driven"],
|
|
6
6
|
"repository": {
|