maxserver 0.1.24 → 0.1.30
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 +76 -51
- package/bin/init.js +0 -0
- package/package.json +1 -1
- package/src/devSounds.js +8 -2
- package/src/index.js +4 -1
- package/src/setupDocs.js +5 -2
- package/src/setupRoutes.js +8 -18
- package/templates/package.json +16 -1
- package/TODO.md +0 -4
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# maxserver
|
|
2
|
-
|
|
3
|
-
Just a Node server setup based on **Fastify** to speed up backend development.
|
|
2
|
+
Node server setup based on **Fastify** to speed up backend development.
|
|
4
3
|
maxserver stands for **maximized simplicity** and **minimum boilerplate**.
|
|
5
4
|
|
|
6
5
|
- **Auto Routes**: auto imports and registers routes and schemas
|
|
@@ -32,7 +31,7 @@ export default server;
|
|
|
32
31
|
|
|
33
32
|
## ⚙️ Configure
|
|
34
33
|
Configs can be passed to the init call to **maxserver()** or set in your .env file.
|
|
35
|
-
If you define options in env, use all upper case letters.
|
|
34
|
+
If you define options in env, use all upper case letters.
|
|
36
35
|
Any fastify options can be passed to maxserver() too.
|
|
37
36
|
|
|
38
37
|
|
|
@@ -40,8 +39,8 @@ Any fastify options can be passed to maxserver() too.
|
|
|
40
39
|
| :--- | :--- | :--- |
|
|
41
40
|
| `port` | `3000` | Server port |
|
|
42
41
|
| `secret` | *-* | Secret used for jwt and cookies |
|
|
43
|
-
| `cors` | `*` |
|
|
44
|
-
| `docs` | `true` | Set `false` to disable auto generated docs
|
|
42
|
+
| `cors` | `*` | Default all allowed |
|
|
43
|
+
| `docs` | `true` | Set `false` to disable auto generated docs |
|
|
45
44
|
| `mongodb` | *-* | MongoDB URI, if set auto-connects db |
|
|
46
45
|
| `public` | `false` | Set `true` to expose the server publicly (binds to `0.0.0.0`) |
|
|
47
46
|
| `static` | *-* | If set, serves this directory statically |
|
|
@@ -50,29 +49,15 @@ Any fastify options can be passed to maxserver() too.
|
|
|
50
49
|
|
|
51
50
|
<br>
|
|
52
51
|
|
|
53
|
-
## 🗂️ Project Structure
|
|
54
|
-
Our golden rule: **1 route = 1 handler file + 1 schema file**
|
|
55
52
|
|
|
56
|
-
|
|
53
|
+
## 🤖 Auto Routing
|
|
54
|
+
Routes are auto registered based on one small comment per file:
|
|
57
55
|
|
|
58
56
|
```
|
|
59
|
-
|
|
60
|
-
users/
|
|
61
|
-
teams/
|
|
62
|
-
forms/
|
|
63
|
-
hello.js
|
|
64
|
-
hello.schema.js
|
|
65
|
-
...
|
|
57
|
+
// METHOD /path
|
|
66
58
|
```
|
|
67
59
|
<br>
|
|
68
60
|
|
|
69
|
-
## 🤖 Auto Routing
|
|
70
|
-
|
|
71
|
-
To auto-register routes, simple add a comment of the form:
|
|
72
|
-
**// METHOD /path**
|
|
73
|
-
**// GET /user**
|
|
74
|
-
**// POST /feedback/something**
|
|
75
|
-
...
|
|
76
61
|
|
|
77
62
|
```js
|
|
78
63
|
// GET /hello
|
|
@@ -87,22 +72,33 @@ export default async function handler(req, rep) {
|
|
|
87
72
|
}
|
|
88
73
|
```
|
|
89
74
|
<br>
|
|
90
|
-
|
|
91
|
-
And remember to use default export for your handler.
|
|
92
|
-
If you don't want to autoregister some routes, then simply don't add that magic comment 😃
|
|
93
|
-
That's it.
|
|
94
|
-
|
|
95
75
|
|
|
76
|
+
Doesn't matter how nested your path is or how many params,
|
|
77
|
+
It always works this simple and you are free to position your files the way you like.
|
|
78
|
+
If you don't want to autoregister some files, then simply don't add that magic comment 😃
|
|
96
79
|
<br>
|
|
97
80
|
<br>
|
|
81
|
+
```
|
|
82
|
+
// GET /teams/:teamid
|
|
83
|
+
// PATCH /forms/:formId/questions/:questionId
|
|
84
|
+
...
|
|
85
|
+
```
|
|
86
|
+
<br/>
|
|
98
87
|
|
|
88
|
+
### 3 RULES
|
|
89
|
+
1. Add magic comment
|
|
90
|
+
2. Default export handler
|
|
91
|
+
3. One handler per file
|
|
99
92
|
|
|
100
|
-
|
|
101
|
-
Create a sibling file ending with **`.schema.js`**, so it will be auto registered. For example: **hello.js** and **hello.schema.js**
|
|
93
|
+
<br>
|
|
102
94
|
|
|
103
|
-
Besides the basic validation fields we can set fields like summary and description, which will appear in the docs. Mostly you don't need to write schemas yourself, chat gpt and gemini do it excelently.
|
|
104
95
|
|
|
96
|
+
## 🧾 Schemas
|
|
97
|
+
Files ending with **`.schema.js`** will be auto registered.
|
|
98
|
+
For example: **hello.js** and **hello.schema.js**
|
|
105
99
|
|
|
100
|
+
Besides the basic validation fields we can set fields like `tags`, `summary` and description,
|
|
101
|
+
which will appear in the docs.
|
|
106
102
|
|
|
107
103
|
|
|
108
104
|
```js
|
|
@@ -126,38 +122,30 @@ export default {
|
|
|
126
122
|
};
|
|
127
123
|
```
|
|
128
124
|
|
|
129
|
-
|
|
130
|
-
|
|
125
|
+
**‼️ Important use export default**
|
|
126
|
+
Some examples in the template folder.
|
|
131
127
|
|
|
132
|
-
<br>
|
|
133
|
-
|
|
134
|
-
## 🛠️ Route Options
|
|
135
|
-
Though we don't mostly register routes manually, we don't set route options on the register call.
|
|
136
|
-
If needed, you can wether register that route manually or just set them on the schema.
|
|
137
128
|
|
|
138
|
-
|
|
139
|
-
|
|
129
|
+
### MODELS
|
|
130
|
+
You can also auto register **models** (schemas which are shared between multiple routes).
|
|
131
|
+
For example `User.schema.js`. It "magically" understand the difference betwen route specific
|
|
132
|
+
schema or generic model, by looking if a sibling file exist or not 😉
|
|
140
133
|
|
|
141
|
-
|
|
142
|
-
routeOptions: {
|
|
143
|
-
config: {
|
|
144
|
-
preHandler: ...
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
...
|
|
148
|
-
```
|
|
134
|
+
<br>
|
|
149
135
|
|
|
150
136
|
|
|
151
|
-
<br>
|
|
152
137
|
|
|
153
138
|
## 📚 API Docs
|
|
154
|
-
|
|
155
139
|
Open in your browser **`localhost:3000/docs`**
|
|
156
|
-
|
|
140
|
+
You should find all your routes well documented.
|
|
141
|
+
And you can also easily test any route.
|
|
157
142
|
|
|
158
143
|
<br>
|
|
159
144
|
|
|
160
145
|
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
161
149
|
## 🔐 Authentication
|
|
162
150
|
JWT header and cookie based auth is preconfigured.
|
|
163
151
|
To enable auth for a route set in it's schema **auth = true**
|
|
@@ -171,6 +159,23 @@ export default {
|
|
|
171
159
|
};
|
|
172
160
|
```
|
|
173
161
|
|
|
162
|
+
## 🛠️ Route Options
|
|
163
|
+
Though we don't mostly register routes manually, we don't set route options on the register call.
|
|
164
|
+
If needed, you can wether register that route manually or just set them on the schema.
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
// Inside schema
|
|
168
|
+
|
|
169
|
+
export default {
|
|
170
|
+
routeOptions: {
|
|
171
|
+
config: {
|
|
172
|
+
preHandler: ...
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
...
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
<br>
|
|
174
179
|
<br>
|
|
175
180
|
|
|
176
181
|
## 🍃 MongoDB
|
|
@@ -210,8 +215,28 @@ Rule of thumb: make the message something you would want to see at 03:00 in logs
|
|
|
210
215
|
|
|
211
216
|
<br>
|
|
212
217
|
|
|
218
|
+
|
|
219
|
+
|
|
213
220
|
## About
|
|
214
221
|
- Dependencies: original fastify packages + scalar/fastify-api-reference
|
|
215
222
|
- The source is simple. Everyone can read, understand and modify if needed.
|
|
216
223
|
|
|
217
|
-
|
|
224
|
+
|
|
225
|
+
## Todo
|
|
226
|
+
- document how to add fastify hooks
|
|
227
|
+
- document how to pass scalar options
|
|
228
|
+
- more example and best practises
|
|
229
|
+
- document project setup with npx
|
|
230
|
+
- npx option, atm devserver macos only
|
|
231
|
+
- unit tests
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
I am just starting to publish packages on github / npm.
|
|
235
|
+
Still not sure if it's worth the time 😃
|
|
236
|
+
|
|
237
|
+
If anyone else than me and bots is using this package,
|
|
238
|
+
just follow me on github and I will improve it.
|
|
239
|
+
|
|
240
|
+
https://github.com/max-matinpalo
|
|
241
|
+
|
|
242
|
+
```
|
package/bin/init.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/src/devSounds.js
CHANGED
|
@@ -20,9 +20,15 @@ export async function setupDevSounds(app) {
|
|
|
20
20
|
|
|
21
21
|
app.addHook('onResponse', async (req, reply) => {
|
|
22
22
|
|
|
23
|
-
//
|
|
23
|
+
// Dev sounds only for api requests - not for static served files 😃
|
|
24
24
|
const ct = String(reply.getHeader('content-type') || '').toLowerCase();
|
|
25
|
-
|
|
25
|
+
const disabled = req.routeOptions?.config?.devSound === false;
|
|
26
|
+
let trigger = ct && ct.includes('application/json') && !disabled;
|
|
27
|
+
|
|
28
|
+
// Though this is route is auto registered by scalar, and we can't set sounds false on it...
|
|
29
|
+
if (req.url === "/docs/openapi.json") return;
|
|
30
|
+
|
|
31
|
+
if (trigger) {
|
|
26
32
|
const code = reply.statusCode;
|
|
27
33
|
if (code < 400) play(ok);
|
|
28
34
|
else play(err);
|
package/src/index.js
CHANGED
|
@@ -17,6 +17,8 @@ import { setupDevSounds } from "./devSounds.js";
|
|
|
17
17
|
|
|
18
18
|
export default async function maxserver(config = {}) {
|
|
19
19
|
|
|
20
|
+
console.log("local one running 3");
|
|
21
|
+
|
|
20
22
|
const {
|
|
21
23
|
|
|
22
24
|
// maxserver options
|
|
@@ -71,6 +73,7 @@ export default async function maxserver(config = {}) {
|
|
|
71
73
|
console.log('Server running at ', getAddress(this));
|
|
72
74
|
});
|
|
73
75
|
|
|
76
|
+
await setupDevSounds(app);
|
|
74
77
|
await setupCookie(app);
|
|
75
78
|
await setupHelmet(app);
|
|
76
79
|
await setupCors(app);
|
|
@@ -79,7 +82,7 @@ export default async function maxserver(config = {}) {
|
|
|
79
82
|
await setupStatic(app);
|
|
80
83
|
await setupDocs(app);
|
|
81
84
|
await setupRoutes(app);
|
|
82
|
-
|
|
85
|
+
|
|
83
86
|
|
|
84
87
|
global.createError = function (code, message) {
|
|
85
88
|
const err = new Error(message);
|
package/src/setupDocs.js
CHANGED
|
@@ -2,7 +2,7 @@ import swagger from "@fastify/swagger";
|
|
|
2
2
|
import apiReference from "@scalar/fastify-api-reference";
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/*
|
|
6
6
|
const schema = {
|
|
7
7
|
summary: "OpenAPI Specification",
|
|
8
8
|
description: "Returns the full OpenAPI 3.0 specification.",
|
|
@@ -27,6 +27,7 @@ const schema = {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
|
+
*/
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
|
|
@@ -53,8 +54,9 @@ export async function setupDocs(app) {
|
|
|
53
54
|
},
|
|
54
55
|
});
|
|
55
56
|
|
|
57
|
+
// not needed, the scalar extension provides it by default on /docs/openapi.json
|
|
58
|
+
// app.get("/openapi.json", {schema}, () => app.swagger());
|
|
56
59
|
|
|
57
|
-
app.get("/openapi.json", { schema }, () => app.swagger());
|
|
58
60
|
|
|
59
61
|
if (app.maxserver.docs !== false)
|
|
60
62
|
await app.register(apiReference, {
|
|
@@ -67,6 +69,7 @@ export async function setupDocs(app) {
|
|
|
67
69
|
telemetry: false,
|
|
68
70
|
persistAuth: true,
|
|
69
71
|
showDeveloperTools: "never",
|
|
72
|
+
//"expandAllModelSections": true,
|
|
70
73
|
operationsSorter: "alpha",
|
|
71
74
|
orderSchemaPropertiesBy: "preserve",
|
|
72
75
|
metaData: {
|
package/src/setupRoutes.js
CHANGED
|
@@ -65,23 +65,6 @@ export async function setupRoutes(app) {
|
|
|
65
65
|
const root = path.resolve(app.maxserver.routesDir || "src");
|
|
66
66
|
const files = walk(root);
|
|
67
67
|
|
|
68
|
-
/*
|
|
69
|
-
// Old one which only graps default exports
|
|
70
|
-
|
|
71
|
-
// 1. Pass One: Register Global Schemas (Lonely .schema.js files)
|
|
72
|
-
for (const file of files) {
|
|
73
|
-
if (file.endsWith(".schema.js")) {
|
|
74
|
-
const hasHandler = fs.existsSync(file.replace(".schema.js", ".js"));
|
|
75
|
-
|
|
76
|
-
if (!hasHandler) {
|
|
77
|
-
const schema = await importDefault(file);
|
|
78
|
-
if (schema?.$id) app.addSchema(schema);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
*/
|
|
83
|
-
|
|
84
|
-
|
|
85
68
|
// 1. Pass One: Register Global Schemas (Lonely .schema.js files)
|
|
86
69
|
for (const file of files) {
|
|
87
70
|
// Only process if no matching handler file exists
|
|
@@ -94,7 +77,14 @@ export async function setupRoutes(app) {
|
|
|
94
77
|
}
|
|
95
78
|
}
|
|
96
79
|
|
|
97
|
-
// 2. Pass Two:
|
|
80
|
+
// 2. Pass Two: Auto-register hooks
|
|
81
|
+
for (const file of files) {
|
|
82
|
+
const mod = await import(pathToFileURL(file).href);
|
|
83
|
+
for (const [key, fn] of Object.entries(mod))
|
|
84
|
+
if (key.startsWith("autoregister_") && typeof fn === "function") await fn(app);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 3. Pass Three: Register Routes
|
|
98
88
|
const seen = new Map();
|
|
99
89
|
for (const file of files) {
|
|
100
90
|
if (file.endsWith(".schema.js")) continue;
|
package/templates/package.json
CHANGED
|
@@ -9,5 +9,20 @@
|
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
11
|
"private": "true",
|
|
12
|
-
"dependencies": {}
|
|
12
|
+
"dependencies": {},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"fastify",
|
|
15
|
+
"backend",
|
|
16
|
+
"framework",
|
|
17
|
+
"node-server",
|
|
18
|
+
"api-server",
|
|
19
|
+
"auto-routes",
|
|
20
|
+
"automatic-docs",
|
|
21
|
+
"scalar",
|
|
22
|
+
"openapi",
|
|
23
|
+
"jwt-auth",
|
|
24
|
+
"mongodb",
|
|
25
|
+
"minimalist",
|
|
26
|
+
"zero-boilerplate"
|
|
27
|
+
]
|
|
13
28
|
}
|
package/TODO.md
DELETED