@magek/mcp-server 0.0.8
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 +42 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +25 -0
- package/dist/prompts/cqrs-flow.d.ts +15 -0
- package/dist/prompts/cqrs-flow.js +252 -0
- package/dist/prompts/troubleshooting.d.ts +15 -0
- package/dist/prompts/troubleshooting.js +239 -0
- package/dist/resources/cli-reference.d.ts +13 -0
- package/dist/resources/cli-reference.js +193 -0
- package/dist/resources/documentation.d.ts +18 -0
- package/dist/resources/documentation.js +62 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +127 -0
- package/dist/utils/docs-loader.d.ts +19 -0
- package/dist/utils/docs-loader.js +111 -0
- package/docs/advanced/custom-templates.md +96 -0
- package/docs/advanced/data-migrations.md +181 -0
- package/docs/advanced/environment-configuration.md +74 -0
- package/docs/advanced/framework-packages.md +17 -0
- package/docs/advanced/health/sensor-health.md +389 -0
- package/docs/advanced/instrumentation.md +135 -0
- package/docs/advanced/register.md +119 -0
- package/docs/advanced/sensor.md +10 -0
- package/docs/advanced/testing.md +96 -0
- package/docs/advanced/touch-entities.md +45 -0
- package/docs/architecture/command.md +367 -0
- package/docs/architecture/entity.md +214 -0
- package/docs/architecture/event-driven.md +30 -0
- package/docs/architecture/event-handler.md +108 -0
- package/docs/architecture/event.md +145 -0
- package/docs/architecture/notifications.md +54 -0
- package/docs/architecture/queries.md +207 -0
- package/docs/architecture/read-model.md +507 -0
- package/docs/contributing.md +349 -0
- package/docs/docs-index.json +200 -0
- package/docs/features/error-handling.md +204 -0
- package/docs/features/event-stream.md +35 -0
- package/docs/features/logging.md +81 -0
- package/docs/features/schedule-actions.md +44 -0
- package/docs/getting-started/ai-coding-assistants.md +181 -0
- package/docs/getting-started/coding.md +543 -0
- package/docs/getting-started/installation.md +143 -0
- package/docs/graphql.md +1213 -0
- package/docs/index.md +62 -0
- package/docs/introduction.md +58 -0
- package/docs/magek-arch.png +0 -0
- package/docs/magek-cli.md +67 -0
- package/docs/magek-logo.svg +1 -0
- package/docs/security/authentication.md +189 -0
- package/docs/security/authorization.md +242 -0
- package/docs/security/security.md +16 -0
- package/package.json +46 -0
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Coding Tutorial"
|
|
3
|
+
group: "Getting Started"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build a Magek app in minutes
|
|
7
|
+
|
|
8
|
+
In this section, we will go through all the necessary steps to have the backend up and
|
|
9
|
+
running for a blog application in just a few minutes.
|
|
10
|
+
|
|
11
|
+
Before starting, make sure you have [Node.js installed](/getting-started/installation). You'll need the Magek CLI later for development tasks, but project creation doesn't require any global installations.
|
|
12
|
+
|
|
13
|
+
### 1. Create the project
|
|
14
|
+
|
|
15
|
+
In your favourite terminal, run this command:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm create magek@latest boosted-blog
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The create script will prompt you for project details like description, author, and license. You can press Enter to accept the defaults for any field. The script automatically configures your project to use **Magek Server**, which allows you to run and debug your application locally.
|
|
22
|
+
|
|
23
|
+
After filling in the details, you will see your project generated!:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
📦 Creating project...
|
|
27
|
+
✓ Template copied
|
|
28
|
+
🔧 Configuring project...
|
|
29
|
+
✓ Project configured
|
|
30
|
+
📦 Installing dependencies...
|
|
31
|
+
✓ Dependencies installed
|
|
32
|
+
🔄 Initializing git repository...
|
|
33
|
+
✓ Git repository initialized
|
|
34
|
+
|
|
35
|
+
🎉 Project created successfully!
|
|
36
|
+
|
|
37
|
+
Next steps:
|
|
38
|
+
cd boosted-blog
|
|
39
|
+
nvm use
|
|
40
|
+
npm install
|
|
41
|
+
npx magek version
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> **Tip:** You can create a project non-interactively by providing command line options:
|
|
45
|
+
>
|
|
46
|
+
> ```shell
|
|
47
|
+
> npm create magek@latest my-app -- --author "Your Name" --description "My awesome Magek app"
|
|
48
|
+
> ```
|
|
49
|
+
>
|
|
50
|
+
> Available options:
|
|
51
|
+
> - `--author` - Author of the project
|
|
52
|
+
> - `--description` - Project description
|
|
53
|
+
> - `--license` - License (defaults to MIT)
|
|
54
|
+
> - `--skip-install` - Skip npm install
|
|
55
|
+
> - `--skip-git` - Skip git repository initialization
|
|
56
|
+
> - `--package-manager` - Package manager to use (npm or pnpm, defaults to npm)
|
|
57
|
+
> - `--template` - Custom template from GitHub (e.g., user/repo-name)
|
|
58
|
+
|
|
59
|
+
> The `npm create` command follows the modern npm ecosystem pattern for project scaffolding:
|
|
60
|
+
>
|
|
61
|
+
> - `npm create` uses the standard npm create pattern (similar to `create-react-app`, `create-next-app`)
|
|
62
|
+
> - `magek@latest` specifies the package name and version to use for creating projects
|
|
63
|
+
> - `boosted-blog` is the name of the project directory to create
|
|
64
|
+
>
|
|
65
|
+
> This approach requires no global installations - just npm v7+ which comes with Node.js.
|
|
66
|
+
|
|
67
|
+
> **Tip:** You can also use equivalent commands with other package managers:
|
|
68
|
+
> - `npx create-magek@latest boosted-blog`
|
|
69
|
+
> - `pnpm dlx create-magek@latest boosted-blog`
|
|
70
|
+
> - `bun create magek boosted-blog`
|
|
71
|
+
|
|
72
|
+
When finished, you'll see some scaffolding that has been generated. The project name will be the
|
|
73
|
+
project's root so `cd` into it:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cd boosted-blog
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
There you should have these files and directories already generated:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
boosted-blog
|
|
83
|
+
├── .eslintignore
|
|
84
|
+
├── .gitignore
|
|
85
|
+
├── .eslintrc.js
|
|
86
|
+
├── .prettierrc.yaml
|
|
87
|
+
├── package-lock.json
|
|
88
|
+
├── package.json
|
|
89
|
+
├── src
|
|
90
|
+
│ ├── commands
|
|
91
|
+
│ ├── common
|
|
92
|
+
│ ├── config
|
|
93
|
+
│ │ └── config.ts
|
|
94
|
+
│ ├── entities
|
|
95
|
+
│ ├── events
|
|
96
|
+
│ ├── event-handlers
|
|
97
|
+
│ ├── read-models
|
|
98
|
+
│ └── index.ts
|
|
99
|
+
├── tsconfig.eslint.json
|
|
100
|
+
└── tsconfig.json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Now open the project in your favorite editor, e.g. [Visual Studio Code](https://code.visualstudio.com/).
|
|
104
|
+
|
|
105
|
+
### 2. Setting up your development environment
|
|
106
|
+
|
|
107
|
+
Now that you have a project, navigate to your project directory and set up your development environment. The project includes the Magek CLI as a dependency, so you can use it immediately:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
cd boosted-blog
|
|
111
|
+
nvm use
|
|
112
|
+
npm install
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
You can verify everything is working by running:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npx magek version
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. First command
|
|
122
|
+
|
|
123
|
+
Commands define the input to our system, so we'll start by generating our first
|
|
124
|
+
[command](/architecture/command) to create posts. Use the command generator, while in the project's root
|
|
125
|
+
directory, as follows:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npx magek new:command CreatePost --fields postId:UUID title:string content:string author:string
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The `new:command` generator creates a `create-post.ts` file in the `commands` folder:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
boosted-blog
|
|
135
|
+
└── src
|
|
136
|
+
└── commands
|
|
137
|
+
└── create-post.ts
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
As we mentioned before, commands are the input of our system. They're sent
|
|
141
|
+
by the users of our application. When they are received you can validate its data,
|
|
142
|
+
execute some business logic, and register one or more events. Therefore, we have to define two more things:
|
|
143
|
+
|
|
144
|
+
1. Who is authorized to run this command.
|
|
145
|
+
1. The events that it will trigger.
|
|
146
|
+
|
|
147
|
+
Magek allows you to define authorization strategies (we will cover that
|
|
148
|
+
later). Let's start by allowing anyone to send this command to our application.
|
|
149
|
+
To do that, open the file we have just generated and add the string `'all'` to the
|
|
150
|
+
`authorize` parameter of the `@Command` decorator. Your `CreatePost` command should look like this:
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
@Command({
|
|
154
|
+
authorize: 'all', // Specify authorized roles here. Use 'all' to authorize anyone
|
|
155
|
+
})
|
|
156
|
+
export class CreatePost {
|
|
157
|
+
@field()
|
|
158
|
+
readonly postId!: UUID
|
|
159
|
+
|
|
160
|
+
@field()
|
|
161
|
+
readonly title!: string
|
|
162
|
+
|
|
163
|
+
@field()
|
|
164
|
+
readonly content!: string
|
|
165
|
+
|
|
166
|
+
@field()
|
|
167
|
+
readonly author!: string
|
|
168
|
+
|
|
169
|
+
public static async handle(command: CreatePost, register: Register): Promise<void> {
|
|
170
|
+
register.events(/* YOUR EVENT HERE */)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 4. First event
|
|
176
|
+
|
|
177
|
+
Instead of creating, updating, or deleting objects, Magek stores data in the form of events.
|
|
178
|
+
They are records of facts and represent the source of truth. Let's generate an event called `PostCreated`
|
|
179
|
+
that will contain the initial post info:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npx magek new:event PostCreated --fields postId:UUID title:string content:string author:string
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The `new:event` generator creates a new file under the `src/events` directory.
|
|
186
|
+
The name of the file is the name of the event:
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
boosted-blog
|
|
190
|
+
└── src
|
|
191
|
+
└── events
|
|
192
|
+
└── post-created.ts
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
All events in Magek must target an entity, so we need to implement an `entityID`
|
|
196
|
+
method. From there, we'll return the identifier of the post created, the field
|
|
197
|
+
`postID`. This identifier will be used later by Magek to build the final state
|
|
198
|
+
of the `Post` automatically. Edit the `entityID` method in `events/post-created.ts`
|
|
199
|
+
to return our `postID`:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// src/events/post-created.ts
|
|
203
|
+
|
|
204
|
+
@Event
|
|
205
|
+
export class PostCreated {
|
|
206
|
+
@field()
|
|
207
|
+
public readonly postId!: UUID
|
|
208
|
+
|
|
209
|
+
@field()
|
|
210
|
+
public readonly title!: string
|
|
211
|
+
|
|
212
|
+
@field()
|
|
213
|
+
public readonly content!: string
|
|
214
|
+
|
|
215
|
+
@field()
|
|
216
|
+
public readonly author!: string
|
|
217
|
+
|
|
218
|
+
public constructor(postId: UUID, title: string, content: string, author: string) {
|
|
219
|
+
this.postId = postId
|
|
220
|
+
this.title = title
|
|
221
|
+
this.content = content
|
|
222
|
+
this.author = author
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
public entityID(): UUID {
|
|
226
|
+
return this.postId
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Now that we have an event, we can edit the `CreatePost` command to emit it. Let's change
|
|
232
|
+
the command's `handle` method to look like this:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// src/commands/create-post.ts::handle
|
|
236
|
+
public static async handle(command: CreatePost, register: Register): Promise<void> {
|
|
237
|
+
register.events(new PostCreated(command.postId, command.title, command.content, command.author))
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Remember to import the event class correctly on the top of the file:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
We can do any validation in the command handler before storing the event, for our
|
|
247
|
+
example, we'll just save the received data in the `PostCreated` event.
|
|
248
|
+
|
|
249
|
+
### 5. First entity
|
|
250
|
+
|
|
251
|
+
So far, our `PostCreated` event suggests we need a `Post` entity. Entities are a
|
|
252
|
+
representation of our system internal state. They are in charge of reducing (combining) all the events
|
|
253
|
+
with the same `entityID`. Let's generate our `Post` entity:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
npx magek new:entity Post --fields title:string content:string author:string --reduces PostCreated
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
You should see now a new file called `post.ts` in the `src/entities` directory.
|
|
260
|
+
|
|
261
|
+
This time, besides using the `--fields` flag, we use the `--reduces` flag to specify the events the entity will reduce and, this way, produce the Post current state. The generator will create one _reducer function_ for each event we have specified (only one in this case).
|
|
262
|
+
|
|
263
|
+
Reducer functions in Magek work similarly to the `reduce` callbacks in Javascript: they receive an event
|
|
264
|
+
and the current state of the entity, and returns the next version of the same entity.
|
|
265
|
+
In this case, when we receive a `PostCreated` event, we can just return a new `Post` entity copying the fields
|
|
266
|
+
from the event. There is no previous state of the Post as we are creating it for the first time:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// src/entities/post.ts
|
|
270
|
+
@Entity
|
|
271
|
+
export class Post {
|
|
272
|
+
@field(type => UUID)
|
|
273
|
+
public id!: UUID
|
|
274
|
+
|
|
275
|
+
@field()
|
|
276
|
+
readonly title!: string
|
|
277
|
+
|
|
278
|
+
@field()
|
|
279
|
+
readonly content!: string
|
|
280
|
+
|
|
281
|
+
@field()
|
|
282
|
+
readonly author!: string
|
|
283
|
+
|
|
284
|
+
@reduces(PostCreated)
|
|
285
|
+
public static reducePostCreated(event: PostCreated, currentPost?: Post): Post {
|
|
286
|
+
return evolve(currentPost, {
|
|
287
|
+
id: event.postId,
|
|
288
|
+
title: event.title,
|
|
289
|
+
content: event.content,
|
|
290
|
+
author: event.author,
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Entities represent our domain model and can be queried from command or
|
|
297
|
+
event handlers to make business decisions or enforcing business rules.
|
|
298
|
+
|
|
299
|
+
### 6. First read model
|
|
300
|
+
|
|
301
|
+
In a real application, we rarely want to make public our entire domain model (entities)
|
|
302
|
+
including all their fields. What is more, different users may have different views of the data depending
|
|
303
|
+
on their permissions or their use cases. That's the goal of `ReadModels`. Client applications can query or
|
|
304
|
+
subscribe to them.
|
|
305
|
+
|
|
306
|
+
Read models are _projections_ of one or more entities into a new object that is reachable through the query and subscriptions APIs. Let's generate a `PostReadModel` that projects our
|
|
307
|
+
`Post` entity:
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
npx magek new:read-model PostReadModel --fields title:string author:string --projects Post:id
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
We have used a new flag, `--projects`, that allow us to specify the entities (can be many) the read model will
|
|
314
|
+
watch for changes. You might be wondering what is the `:id` after the entity name. That's the [joinKey](/architecture/read-model#the-projection-function),
|
|
315
|
+
but you can forget about it now.
|
|
316
|
+
|
|
317
|
+
As you might guess, the read-model generator will create a file called
|
|
318
|
+
`post-read-model.ts` under `src/read-models`:
|
|
319
|
+
|
|
320
|
+
```text
|
|
321
|
+
boosted-blog
|
|
322
|
+
└── src
|
|
323
|
+
└── read-models
|
|
324
|
+
└── post-read-model.ts
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
There are two things to do when creating a read model:
|
|
328
|
+
|
|
329
|
+
1. Define who is authorized to query or subscribe it
|
|
330
|
+
1. Add the logic of the projection functions, where you can filter, combine, etc., the entities fields.
|
|
331
|
+
|
|
332
|
+
While commands define the input to our system, read models define the output, and together they compound
|
|
333
|
+
the public API of a Magek application. Let's do the same we did in the command and authorize `all` to
|
|
334
|
+
query/subscribe the `PostReadModel`. Also, and for learning purposes, we will exclude the `content` field
|
|
335
|
+
from the `Post` entity, so it won't be returned when users request the read model.
|
|
336
|
+
|
|
337
|
+
Edit the `post-read-model.ts` file to look like this:
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
// src/read-models/post-read-model.ts
|
|
341
|
+
@ReadModel({
|
|
342
|
+
authorize: 'all', // Specify authorized roles here. Use 'all' to authorize anyone
|
|
343
|
+
})
|
|
344
|
+
export class PostReadModel {
|
|
345
|
+
@field(type => UUID)
|
|
346
|
+
public id!: UUID
|
|
347
|
+
|
|
348
|
+
@field()
|
|
349
|
+
readonly title!: string
|
|
350
|
+
|
|
351
|
+
@field()
|
|
352
|
+
readonly author!: string
|
|
353
|
+
|
|
354
|
+
@projects(Post, 'id')
|
|
355
|
+
public static projectPost(entity: Post, currentPostReadModel?: PostReadModel): ProjectionResult<PostReadModel> {
|
|
356
|
+
return evolve(currentPostReadModel, {
|
|
357
|
+
id: entity.id,
|
|
358
|
+
title: entity.title,
|
|
359
|
+
author: entity.author,
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 7. Building and Running
|
|
366
|
+
|
|
367
|
+
At this point, we've:
|
|
368
|
+
|
|
369
|
+
- Created a publicly accessible command
|
|
370
|
+
- Emitted an event as a mechanism to store data
|
|
371
|
+
- Reduced the event into an entity to have a representation of our internal state
|
|
372
|
+
- Projected the entity into a read model that is also publicly accessible.
|
|
373
|
+
|
|
374
|
+
With this, you already know the basics to build event-driven, CQRS-based applications
|
|
375
|
+
with Magek.
|
|
376
|
+
|
|
377
|
+
You can check that code compiles correctly by running the build command:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
npm run build
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
You can also clean the compiled code by running:
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
npm run clean
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
#### 7.1 Running your application locally
|
|
390
|
+
|
|
391
|
+
Now, let's run our application to see it working. It is as simple as running:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
npx magek start -e local
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
This will execute a local `Express.js` server and will try to expose it in port `3000`. You can change the port by using the `-p` option:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
npx magek start -e local -p 8080
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Once the server is running, you can access the GraphQL API at the URL shown in the console (typically `http://localhost:3000/graphql`).
|
|
404
|
+
|
|
405
|
+
> **Note:** By default, the full error stack trace is sent to a local file, `./errors.log`. To see the full error stack trace directly from the console, use the `--verbose` flag.
|
|
406
|
+
|
|
407
|
+
### 8. Testing
|
|
408
|
+
|
|
409
|
+
Let's get started testing the project. We will perform three actions:
|
|
410
|
+
|
|
411
|
+
- Add a couple of posts
|
|
412
|
+
- Retrieve all posts
|
|
413
|
+
- Retrieve a specific post
|
|
414
|
+
|
|
415
|
+
Magek applications provide you with a GraphQL API out of the box. You send commands using
|
|
416
|
+
_mutations_ and get read models data using _queries_ or _subscriptions_.
|
|
417
|
+
|
|
418
|
+
In this section, we will be sending requests by hand using the free [Altair](https://altair.sirmuel.design/) GraphQL client,
|
|
419
|
+
which is very simple and straightforward for this guide. However, you can use any client you want. Your endpoint URL should look like this:
|
|
420
|
+
|
|
421
|
+
```text
|
|
422
|
+
<httpURL>/graphql
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
#### 8.1 Creating posts
|
|
426
|
+
|
|
427
|
+
Let's use two mutations to send two `CreatePost` commands.
|
|
428
|
+
|
|
429
|
+
```graphql
|
|
430
|
+
mutation {
|
|
431
|
+
CreatePost(
|
|
432
|
+
input: {
|
|
433
|
+
postId: "95ddb544-4a60-439f-a0e4-c57e806f2f6e"
|
|
434
|
+
title: "Build a blog in 10 minutes with Magek"
|
|
435
|
+
content: "I am so excited to write my first post"
|
|
436
|
+
author: "Boosted developer"
|
|
437
|
+
}
|
|
438
|
+
)
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
```graphql
|
|
443
|
+
mutation {
|
|
444
|
+
CreatePost(
|
|
445
|
+
input: {
|
|
446
|
+
postId: "05670e55-fd31-490e-b585-3a0096db0412"
|
|
447
|
+
title: "Magek framework rocks"
|
|
448
|
+
content: "I am so excited for writing the second post"
|
|
449
|
+
author: "Another boosted developer"
|
|
450
|
+
}
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
The expected response for each of those requests should be:
|
|
456
|
+
|
|
457
|
+
```json
|
|
458
|
+
{
|
|
459
|
+
"data": {
|
|
460
|
+
"CreatePost": true
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
> **Note:** In this example, the IDs are generated on the client-side. When running production applications consider adding validation for ID uniqueness. For this example, we have used [a UUID generator](https://www.uuidgenerator.net/version4)
|
|
466
|
+
|
|
467
|
+
#### 8.2 Retrieving all posts
|
|
468
|
+
|
|
469
|
+
Let's perform a GraphQL `query` that will be hitting our `PostReadModel`:
|
|
470
|
+
|
|
471
|
+
```graphql
|
|
472
|
+
query {
|
|
473
|
+
PostReadModels {
|
|
474
|
+
id
|
|
475
|
+
title
|
|
476
|
+
author
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
It should respond with something like:
|
|
482
|
+
|
|
483
|
+
```json
|
|
484
|
+
{
|
|
485
|
+
"data": {
|
|
486
|
+
"PostReadModels": [
|
|
487
|
+
{
|
|
488
|
+
"id": "05670e55-fd31-490e-b585-3a0096db0412",
|
|
489
|
+
"title": "Magek framework rocks",
|
|
490
|
+
"author": "Another boosted developer"
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"id": "95ddb544-4a60-439f-a0e4-c57e806f2f6e",
|
|
494
|
+
"title": "Build a blog in 10 minutes with Magek",
|
|
495
|
+
"author": "Boosted developer"
|
|
496
|
+
}
|
|
497
|
+
]
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
#### 8.3 Retrieving specific post
|
|
503
|
+
|
|
504
|
+
It is also possible to retrieve specific a `Post` by adding the `id` as input, e.g.:
|
|
505
|
+
|
|
506
|
+
```graphql
|
|
507
|
+
query {
|
|
508
|
+
PostReadModel(id: "95ddb544-4a60-439f-a0e4-c57e806f2f6e") {
|
|
509
|
+
id
|
|
510
|
+
title
|
|
511
|
+
author
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
You should get a response similar to this:
|
|
517
|
+
|
|
518
|
+
```json
|
|
519
|
+
{
|
|
520
|
+
"data": {
|
|
521
|
+
"PostReadModel": {
|
|
522
|
+
"id": "95ddb544-4a60-439f-a0e4-c57e806f2f6e",
|
|
523
|
+
"title": "Build a blog in 10 minutes with Magek",
|
|
524
|
+
"author": "Boosted developer"
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
> Congratulations! You've built an event-driven backend in less than 10 minutes. We hope you have enjoyed discovering the magic of the Magek Framework.
|
|
531
|
+
|
|
532
|
+
### 9. More functionalities
|
|
533
|
+
|
|
534
|
+
This is a really basic example of a Magek application. The are many other features Magek provides like:
|
|
535
|
+
|
|
536
|
+
- Use a more complex authorization schema for commands and read models based on user roles
|
|
537
|
+
- Use GraphQL subscriptions to get updates in real-time
|
|
538
|
+
- Make events trigger other events
|
|
539
|
+
- Reading entities within command handlers to apply domain-driven decisions
|
|
540
|
+
- And much more...
|
|
541
|
+
|
|
542
|
+
Continue reading to dig more. You've just scratched the surface of all the Magek
|
|
543
|
+
capabilities!
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Installation"
|
|
3
|
+
group: "Getting Started"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Installation
|
|
7
|
+
|
|
8
|
+
You can develop with Magek using any of the following operating systems:
|
|
9
|
+
|
|
10
|
+
- Linux
|
|
11
|
+
- macOS
|
|
12
|
+
- Windows (Native and WSL)
|
|
13
|
+
|
|
14
|
+
## Magek Prerequisites
|
|
15
|
+
|
|
16
|
+
### Install Node.js
|
|
17
|
+
|
|
18
|
+
The latest version of Magek (`3.x`) requires the current LTS version of Node.js which is `22.x`. Magek releases with versions `2.x` will only work with the previous Node.js LTS version (`20.x`).
|
|
19
|
+
|
|
20
|
+
> **Info:** For more information on upgrades between Magek v2.x.x and v3.x.x, read [this page](https://github.com/theam/magek/blob/main/upgrade-v3.md).
|
|
21
|
+
>
|
|
22
|
+
> For more information on upgrades between Magek v1.x.x and v2.x.x, read [this page](https://github.com/theam/magek/blob/main/upgrade-v2.md).
|
|
23
|
+
|
|
24
|
+
Download the installer [from Node.js website](https://nodejs.org/en/), or install it using your system's package
|
|
25
|
+
manager.
|
|
26
|
+
|
|
27
|
+
## Windows
|
|
28
|
+
|
|
29
|
+
Using [Chocolatey](https://chocolatey.org/) package manager, run the following command in your PowerShell
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
choco install nodejs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## macOS
|
|
36
|
+
|
|
37
|
+
Using [Homebrew](https://brew.sh) package manager, run the following command on the terminal
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
brew install node
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Ubuntu
|
|
44
|
+
|
|
45
|
+
Just run the following commands on the terminal:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
curl -sL https://deb.nodesource.com/setup_22.x | sudo -E bash -
|
|
49
|
+
sudo apt install nodejs
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Verify that it was installed properly by checking so from your terminal:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
node -v
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> v22.12.0
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm -v
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
> 10.9.1
|
|
65
|
+
|
|
66
|
+
As soon as you have a Node.js version `22.x` or higher, and an `npm` version higher than
|
|
67
|
+
`7`, you are good to go. Just note that `npm` comes with node, you don't have to install
|
|
68
|
+
it apart.
|
|
69
|
+
|
|
70
|
+
Alternatively, we recommend you to use a version manager for dealing with different Node.js
|
|
71
|
+
versions:
|
|
72
|
+
|
|
73
|
+
- [`nvm`](https://github.com/nvm-sh/nvm) - Works with macOS, Linux, and Windows Subsystem
|
|
74
|
+
for Linux
|
|
75
|
+
- [`nvm-windows`](https://github.com/coreybutler/nvm-windows) - Works with native Windows
|
|
76
|
+
|
|
77
|
+
### Install Git
|
|
78
|
+
|
|
79
|
+
Magek will initialize a Git repository when you create a new project (unless you use the `--skipGit` flag), so it is required that you have it already installed in your system.
|
|
80
|
+
|
|
81
|
+
## Windows
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
choco install git
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## macOS
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
brew install git
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Ubuntu
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
sudo apt install git-all
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Git configuration variables
|
|
100
|
+
|
|
101
|
+
After installing git in your machine, make sure that `user.name` and `user.email` are properly configured.
|
|
102
|
+
Take a look at the [Git configuration page](https://git-scm.com/docs/git-config) for more info.
|
|
103
|
+
|
|
104
|
+
To configure them, run in your terminal:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
git config --global user.name "Your Name Here"
|
|
108
|
+
git config --global user.email "your_email@youremail.com"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Creating Projects and Installing the Magek CLI
|
|
112
|
+
|
|
113
|
+
### Quick Start: No Installation Required
|
|
114
|
+
|
|
115
|
+
To create a new Magek project, you don't need to install anything, if you have node installed in your machine, you can run:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm create magek@latest my-project
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This command will create a new project using the latest version without requiring any global installations.
|
|
122
|
+
|
|
123
|
+
### Installing the Magek CLI (No Global Installation Required)
|
|
124
|
+
|
|
125
|
+
For project development after creation, Magek includes the CLI as a dependency in your project. There's no need for global installation - the CLI is automatically available via `npx` after creating your project.
|
|
126
|
+
|
|
127
|
+
When you create a project using `npm create magek@latest`, the CLI is added as a dependency and can be used immediately:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd my-project
|
|
131
|
+
npm install
|
|
132
|
+
npx magek version
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Verify the Magek CLI installation with the `npx magek version` command. You should get back something like
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npx magek version
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
> @magek/cli/0.16.1 darwin-x64 node-v22.12.0
|
|
142
|
+
|
|
143
|
+
> **Tip:** The CLI is automatically included in every Magek project - no global installation needed! Use `npx magek` for all CLI commands within your project directory.
|