@alevnyacow/nzmt 0.22.3 → 0.22.5
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 +85 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -145,6 +145,91 @@ export default async function Page() {
|
|
|
145
145
|
| `npx nzmt s <name>` | **s**ervice |`i:UserStore,Logger` will automatically inject `UserStore` and `Logger`. E.g. `npx nzmt s shop i:UserStore,ProductStore` will create `ShopService` with already injected `UserStore` and `ProductStore`|
|
|
146
146
|
| `npx nzmt c <name>` | **c**ontroller |`i:UserService` will automatically inject `UserService`. `Logger` and `Guards` are injected by default regardless of `i:` option|
|
|
147
147
|
|
|
148
|
+
# How to implement your own methods
|
|
149
|
+
|
|
150
|
+
## Module contracts as Zod schemas
|
|
151
|
+
|
|
152
|
+
Server module methods are described using Zod schemas. NZMT uses fancy word `metadata` for such contracts, so they can be found in separated files like `user.controller.metadata.ts` or `product.service.metadata.ts`. Besides runtime safety, they’re easy to reuse across layers—no need for separate DTOs.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
// ...some service metadata schemas
|
|
156
|
+
orderDetais: {
|
|
157
|
+
payload: Order.schema.pick({
|
|
158
|
+
name: true,
|
|
159
|
+
createdDate: true
|
|
160
|
+
}),
|
|
161
|
+
response: z.object({
|
|
162
|
+
user: User.schema,
|
|
163
|
+
products: z.array(Product.schema.omit({ price: true }))
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
// ...some service metadata schemas
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**All types and keys are infered, no need to worry about TypeScript.**
|
|
170
|
+
|
|
171
|
+
## Services
|
|
172
|
+
|
|
173
|
+
To add a method:
|
|
174
|
+
|
|
175
|
+
1. **Describe it in metadata schemas** using Zod (`service-name.service.metadata.ts`):
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
foo: {
|
|
179
|
+
request: z.object({ requestString: z.string() }),
|
|
180
|
+
response: z.object({ responseNumber: z.number() })
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
2. **Implement it in the service class** (`service-name.service.ts`):
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
// 'foo' is strongly-typed, don't worry
|
|
188
|
+
foo = this.methods('foo', async ({ requestString }) => {
|
|
189
|
+
// all input and types are also infered
|
|
190
|
+
return Number(requestString)
|
|
191
|
+
})
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Controllers
|
|
195
|
+
|
|
196
|
+
Same idea and types inference, but metadata consists of `query`, `body`, and `response`.
|
|
197
|
+
|
|
198
|
+
1. **Metadata** (`controller-name.controller.metadata.ts`):
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
POST: {
|
|
202
|
+
query: z.object({ id: z.string() }),
|
|
203
|
+
body: z.object({ delta: z.number() }),
|
|
204
|
+
response: z.object({ success: z.boolean() })
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
2. **Implementation** (`controller-name.controller.ts`):
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// `query` and `body` are merged into a single payload
|
|
212
|
+
POST = this.endpoints('POST', async ({ id, delta }) => {
|
|
213
|
+
return { success: true }
|
|
214
|
+
})
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
This method can be used directly as a Next.js API route handler. If you examine generated API route files you will see something like this:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
// api/user-controller/route.ts
|
|
221
|
+
import { fromDI } from '@/server/di'
|
|
222
|
+
import type { UserController } from '@/server/controllers/user'
|
|
223
|
+
|
|
224
|
+
const controller = fromDI<UserController>('UserController')
|
|
225
|
+
|
|
226
|
+
export const GET = controller.GET
|
|
227
|
+
export const PUT = controller.PUT
|
|
228
|
+
export const PATCH = controller.PATCH
|
|
229
|
+
export const DELETE = controller.DELETE
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
|
|
148
233
|
# FAQ
|
|
149
234
|
|
|
150
235
|
## What does DDD-inspired mean?
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alevnyacow/nzmt",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.5",
|
|
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": {
|