kaelum 1.2.0 โ†’ 1.3.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 CHANGED
@@ -1,151 +1,248 @@
1
1
  # Kaelum
2
2
 
3
- **Kaelum** is a minimalist Node.js framework designed to simplify the creation of web pages and REST APIs, especially for beginners and students. Inspired by Python's clean syntax and powered by Express.js, Kaelum automates project setup and server configuration with an intuitive CLI.
3
+ **Kaelum.JS** โ€” Minimalist Node.js framework to simplify creation of web pages and REST APIs.
4
+ Designed for students and developers who want a fast, opinionated project scaffold and a small, friendly API that encapsulates common Express.js boilerplate.
4
5
 
5
- ## ๐Ÿ“ฆ Installation
6
+ ---
7
+
8
+ ## ๐Ÿš€ Quick start
6
9
 
7
- You can create a new project with Kaelum using:
10
+ Create a new project (interactive):
8
11
 
9
12
  ```bash
10
13
  npx kaelum create
11
14
  ````
12
15
 
13
- This command initializes a Kaelum project with a pre-configured structure based on the MVC model, including:
16
+ Or create non-interactively (project name + template):
14
17
 
15
- * Static file serving
16
- * Template-ready HTML/CSS homepage
17
- * Built-in route system
18
- * Public folder and initial structure
18
+ ```bash
19
+ npx kaelum create my-app --template web
20
+ # or
21
+ npx kaelum create my-api --template api
22
+ ```
19
23
 
20
- Then install dependencies and start your app:
24
+ Then:
21
25
 
22
26
  ```bash
23
- cd my-project
27
+ cd my-app
24
28
  npm install
25
29
  npm start
26
30
  ```
27
31
 
28
- > **Note:** No need to install Kaelum globally. `npx` handles it automatically!
32
+ > No need to install Kaelum globally โ€” `npx` handles execution.
29
33
 
30
34
  ---
31
35
 
32
- ## ๐Ÿง  Why Kaelum?
36
+ ## ๐Ÿ“ฆ What Kaelum provides
33
37
 
34
- * ๐Ÿ“‚ Minimalist MVC folder structure
35
- * โš™๏ธ Auto-configured Express setup
36
- * ๐Ÿ”’ Built-in support for CORS and Helmet
37
- * ๐Ÿงฑ Easy route management
38
- * ๐Ÿงช Great for learning and building quick prototypes
38
+ * CLI that scaffolds a ready-to-run project (Web or API template) using an opinionated **MVC** structure.
39
+ * Thin abstraction layer over **Express.js** that:
40
+
41
+ * automates JSON / URL-encoded parsing by default,
42
+ * automatically configures common security middlewares via `setConfig` (CORS, Helmet),
43
+ * exposes a small, easy-to-learn API for routes, middleware and configuration.
44
+ * Small set of helpers for common tasks: `start`, `addRoute`, `apiRoute`, `setConfig`, `static`, `redirect`, `healthCheck`, `useErrorHandler`, and more.
45
+
46
+ Kaelum aims to reduce the initial setup burden while keeping flexibility for advanced users.
39
47
 
40
48
  ---
41
49
 
42
- ## ๐Ÿ“ Web Template Structure
50
+ ## ๐Ÿ“ Template structures
43
51
 
44
- After running `npx kaelum create` using the WEB template, the structure looks like this:
52
+ ### Web template (created by `npx kaelum create <name>` with template `web`)
45
53
 
46
54
  ```
47
55
  my-web-app/
48
- โ”œโ”€โ”€ public/ # Static files (e.g., CSS, JS)
56
+ โ”œโ”€โ”€ public/ # Static files (CSS, JS)
49
57
  โ”‚ โ””โ”€โ”€ style.css
50
58
  โ”œโ”€โ”€ views/ # HTML templates
51
59
  โ”‚ โ””โ”€โ”€ index.html
52
- โ”œโ”€โ”€ controllers/ # Page controller logic
60
+ โ”œโ”€โ”€ controllers/ # Controller logic (MVC)
53
61
  โ”‚ โ””โ”€โ”€ .gitkeep
54
62
  โ”œโ”€โ”€ middlewares/ # Custom middlewares
55
- โ”‚ โ””โ”€โ”€ example.js
56
- โ”œโ”€โ”€ routes.js # Route definitions
57
- โ”œโ”€โ”€ app.js # Server initialization
58
- โ””โ”€โ”€ package.json # Project metadata and dependencies
63
+ โ”‚ โ””โ”€โ”€ logger.js
64
+ โ”œโ”€โ”€ routes.js # Route definitions (example uses Kaelum helpers)
65
+ โ”œโ”€โ”€ app.js # Server initialization (uses Kaelum API)
66
+ โ””โ”€โ”€ package.json
59
67
  ```
60
68
 
61
- ---
62
-
63
- ## ๐Ÿ“ API Template Structure
64
-
65
- After running `npx kaelum create` using the API template, the structure looks like this:
69
+ ### API template (`--template api`)
66
70
 
67
71
  ```
68
72
  my-api-app/
69
73
  โ”œโ”€โ”€ controllers/
70
- โ”‚ โ””โ”€โ”€ userController.js
74
+ โ”‚ โ””โ”€โ”€ usersController.js
71
75
  โ”œโ”€โ”€ middlewares/
72
- โ”‚ โ””โ”€โ”€ logger.js
76
+ โ”‚ โ””โ”€โ”€ authMock.js
73
77
  โ”œโ”€โ”€ routes.js
74
78
  โ”œโ”€โ”€ app.js
75
- โ”œโ”€โ”€ package.json
79
+ โ””โ”€โ”€ package.json
76
80
  ```
77
81
 
78
82
  ---
79
83
 
80
- ## ๐Ÿš€ Features
84
+ ## ๐Ÿงฉ Core API (examples โ€” CommonJS)
81
85
 
82
- Kaelum exposes simple utilities that make it easy to build a web server:
86
+ > Kaelum exposes a factory โ€” use `require('kaelum')` and call it to get an app instance:
83
87
 
84
88
  ```js
85
89
  const kaelum = require('kaelum');
86
90
  const app = kaelum();
87
91
  ```
88
92
 
89
- ### ๐ŸŒ `addRoute(path, handlers)`
93
+ ### `app.setConfig(options)`
90
94
 
91
- Add routes with GET, POST, PUT, DELETE handlers in one place.
95
+ Enable/disable common features:
92
96
 
93
97
  ```js
94
- addRoute('/home', {
95
- get: (req, res) => res.send('GET: Welcome!'),
96
- post: (req, res) => res.send('POST: Data received!')
98
+ app.setConfig({
99
+ cors: true, // apply CORS (requires cors package in dependencies)
100
+ helmet: true, // apply Helmet
101
+ static: "public", // serve static files from "public"
102
+ bodyParser: true, // default: enabled (JSON + urlencoded)
103
+ logs: false, // enable request logging via morgan (if installed)
104
+ port: 3000 // prefered port (used when calling app.start() without port)
97
105
  });
98
106
  ```
99
107
 
100
- ### ๐Ÿ” `setMiddleware(middleware)`
108
+ * `setConfig` persists settings to the Kaelum config and will install/remove Kaelum-managed middlewares.
109
+ * Kaelum enables JSON/urlencoded parsing by default so beginners won't forget to parse request bodies.
101
110
 
102
- Globally apply middleware to all routes.
111
+ ---
112
+
113
+ ### `app.start(port, callback)`
114
+
115
+ Starts the HTTP server. If `port` is omitted, Kaelum reads `port` from `setConfig` or falls back to `3000`.
103
116
 
104
117
  ```js
105
- setMiddleware(require('helmet')());
118
+ app.start(3000, () => console.log('Running'));
106
119
  ```
107
120
 
108
- ### โš™๏ธ `setConfig(options)`
121
+ ---
122
+
123
+ ### `app.addRoute(path, handlers)` and `app.apiRoute(resource, handlers)`
109
124
 
110
- You can enable common configurations using `setConfig`:
125
+ Register routes easily:
111
126
 
112
127
  ```js
113
- app.setConfig({
114
- cors: true,
115
- helmet: true,
128
+ app.addRoute('/home', {
129
+ get: (req, res) => res.send('Welcome!'),
130
+ post: (req, res) => res.send('Posted!')
131
+ });
132
+
133
+ // apiRoute builds RESTy resources with nested subpaths:
134
+ app.apiRoute('users', {
135
+ get: listUsers,
136
+ post: createUser,
137
+ '/:id': {
138
+ get: getUserById,
139
+ put: updateUser,
140
+ delete: deleteUser
141
+ }
116
142
  });
117
143
  ```
118
144
 
119
- Internally, Kaelum will automatically load and apply `cors` and `helmet` if enabled.
145
+ `addRoute` also accepts a single handler function (assumed `GET`).
146
+
147
+ ---
148
+
149
+ ### `app.setMiddleware(...)`
150
+
151
+ Flexible helper to register middleware(s):
152
+
153
+ ```js
154
+ // single middleware
155
+ app.setMiddleware(require('helmet')());
156
+
157
+ // array of middlewares
158
+ app.setMiddleware([mw1, mw2]);
159
+
160
+ // mount middleware on a path
161
+ app.setMiddleware('/admin', authMiddleware);
162
+ ```
163
+
164
+ ---
165
+
166
+ ### `app.redirect(from, to, status)`
167
+
168
+ Register a redirect route:
169
+
170
+ ```js
171
+ app.redirect('/old-url', '/new-url', 302);
172
+ ```
173
+
174
+ ---
175
+
176
+ ### `app.healthCheck(path = '/health')`
177
+
178
+ Adds a health endpoint returning `{ status: 'OK', uptime, timestamp, pid }`.
120
179
 
121
- ### ๐Ÿš€ `start(port)`
180
+ ---
181
+
182
+ ### `app.useErrorHandler(options)`
122
183
 
123
- Start the server.
184
+ Attach Kaelum's default JSON error handler:
124
185
 
125
186
  ```js
126
- start(3000);
187
+ app.useErrorHandler({ exposeStack: false });
127
188
  ```
128
189
 
190
+ It will return standardized JSON for errors and log server-side errors (5xx) to `console.error`.
191
+
129
192
  ---
130
193
 
131
- ## ๐Ÿ‘จโ€๐Ÿ’ป Local Development (for contributors)
194
+ ## ๐Ÿ”ง Local development & contributing
132
195
 
133
- If you want to test or improve Kaelum locally:
196
+ To develop Kaelum locally and test the CLI:
134
197
 
135
198
  ```bash
136
- git clone https://github.com/MatheusCampagnolo/kaelum.git
199
+ # clone
200
+ git clone https://github.com/<your-repo>/kaelum.git
137
201
  cd kaelum
202
+
203
+ # install & link locally
204
+ npm install
138
205
  npm link
206
+
207
+ # from any folder you can now run the CLI
208
+ npx kaelum create my-test --template web
209
+ # or
210
+ kaelum create my-test # if linked globally
139
211
  ```
140
212
 
141
- Now you can run the CLI from anywhere:
213
+ ---
142
214
 
143
- ```bash
144
- npx kaelum create
145
- ```
215
+
216
+ ## ๐Ÿ“ Why Kaelum?
217
+
218
+ * Reduces repetitive boilerplate required to start Node/Express web projects.
219
+ * Opinionated scaffolding (MVC) helps beginners adopt better structure.
220
+ * Keeps a small API surface: easy to teach and document.
221
+ * Extensible โ€” `setConfig` and middleware helpers allow adding features without exposing Express internals.
222
+
223
+ ---
224
+
225
+ ## โœ… Current status
226
+
227
+ > Kaelum is under active development. The CLI scaffolds web and API templates and the framework already includes the MVP helpers (`start`, `addRoute`, `apiRoute`, `setConfig`, `static`, `redirect`, `healthCheck`, `useErrorHandler`) and security toggles for `cors` and `helmet`.
228
+
229
+ ---
230
+
231
+ ## ๐Ÿ“š Links
232
+
233
+ * GitHub: `https://github.com/MatheusCampagnolo/kaelum`
234
+ * npm: `https://www.npmjs.com/package/kaelum`
235
+
236
+ ---
237
+
238
+ ## ๐Ÿงพ License
239
+
240
+ MIT โ€” see [LICENSE](LICENSE).
146
241
 
147
242
  ---
148
243
 
149
- ## ๐Ÿ“„ License
244
+ ## โœ๏ธ Notes for maintainers
150
245
 
151
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
246
+ * Templates include `package.json` configured as `commonjs` for now (uses `require`/`module.exports`).
247
+ * Update template `package.json` dependencies to reference Kaelum version when releasing new npm versions.
248
+ * We plan to add full JSDoc for the public API, unit tests (Jest + Supertest) and a docs site in future iterations.
package/cli/create.js CHANGED
@@ -6,40 +6,80 @@ const { copyTemplate } = require("./utils");
6
6
 
7
7
  const templatesDir = path.resolve(__dirname, "templates");
8
8
 
9
- async function createProject() {
9
+ /**
10
+ * createProject - create project from template
11
+ * @param {Object} defaults - optional { projectName, template }
12
+ */
13
+ async function createProject(defaults = {}) {
10
14
  console.log("๐Ÿš€ Bem-vindo ao Kaelum CLI!");
11
15
 
12
- const answers = await inq.prompt([
13
- {
14
- type: "input",
15
- name: "projectName",
16
- message: "Qual serรก o nome do seu projeto?",
17
- validate: (input) => (input ? true : "O nome nรฃo pode ser vazio."),
18
- },
19
- {
20
- type: "list",
21
- name: "template",
22
- message: "Qual template vocรช deseja usar?",
23
- choices: ["web", "api"],
24
- },
25
- ]);
26
-
27
- const { projectName, template } = answers;
28
- const targetDir = path.resolve(process.cwd(), projectName);
29
- const templateDir = path.join(templatesDir, template);
30
-
31
- if (fs.existsSync(targetDir)) {
32
- console.error(
33
- `\nโŒ A pasta "${projectName}" jรก existe. Escolha outro nome ou apague a pasta existente.`
34
- );
35
- return;
36
- }
16
+ try {
17
+ // ensure templates dir exists
18
+ const templatesExists = await fs.pathExists(templatesDir);
19
+ if (!templatesExists) {
20
+ console.error("โŒ Diretรณrio de templates nรฃo encontrado no CLI.");
21
+ return;
22
+ }
23
+
24
+ // gather answers (use defaults when present)
25
+ const answers = await inq.prompt([
26
+ {
27
+ type: "input",
28
+ name: "projectName",
29
+ message: "Qual serรก o nome do seu projeto?",
30
+ default: defaults.projectName || "",
31
+ validate: (input) => (input ? true : "O nome nรฃo pode ser vazio."),
32
+ },
33
+ {
34
+ type: "list",
35
+ name: "template",
36
+ message: "Qual template vocรช deseja usar?",
37
+ choices: async () => {
38
+ // list available template folders
39
+ try {
40
+ const items = await fs.readdir(templatesDir, {
41
+ withFileTypes: true,
42
+ });
43
+ return items.filter((i) => i.isDirectory()).map((i) => i.name);
44
+ } catch (e) {
45
+ return ["web", "api"];
46
+ }
47
+ },
48
+ default: defaults.template || "web",
49
+ },
50
+ ]);
51
+
52
+ const { projectName, template } = answers;
53
+ const targetDir = path.resolve(process.cwd(), projectName);
54
+ const templateDir = path.join(templatesDir, template);
37
55
 
38
- await copyTemplate(templateDir, targetDir);
56
+ // template existence check
57
+ const templateExists = await fs.pathExists(templateDir);
58
+ if (!templateExists) {
59
+ console.error(`\nโŒ Template "${template}" nรฃo encontrado.`);
60
+ return;
61
+ }
39
62
 
40
- console.log(`\nโœ… Projeto "${projectName}" criado com sucesso!`);
41
- console.log(`โžก๏ธ Acesse a pasta: cd ${projectName}`);
42
- console.log(`โžก๏ธ Inicie o projeto com: npm install && npm start\n`);
63
+ if (await fs.pathExists(targetDir)) {
64
+ console.error(
65
+ `\nโŒ A pasta "${projectName}" jรก existe. Escolha outro nome ou apague a pasta existente.`
66
+ );
67
+ return;
68
+ }
69
+
70
+ // copy + update package.json
71
+ const result = await copyTemplate(templateDir, targetDir, projectName);
72
+ if (!result.ok) {
73
+ console.error(`\nโŒ Erro ao copiar o template: ${result.error}`);
74
+ return;
75
+ }
76
+
77
+ console.log(`\nโœ… Projeto "${projectName}" criado com sucesso!`);
78
+ console.log(`โžก๏ธ Acesse a pasta: cd ${projectName}`);
79
+ console.log(`โžก๏ธ Inicie o projeto com: npm install && npm start\n`);
80
+ } catch (err) {
81
+ console.error("โŒ Erro inesperado:", err.message || err);
82
+ }
43
83
  }
44
84
 
45
- module.exports = { createProject };
85
+ module.exports = { createProject };
package/cli/index.js CHANGED
@@ -1,11 +1,53 @@
1
- #!/usr/bin/env node
2
- const { createProject } = require('./create');
1
+ #!/usr/bin/env node
2
+ const { createProject } = require("./create");
3
+ const argv = process.argv.slice(2);
3
4
 
4
- const [,, command] = process.argv;
5
+ function printHelp() {
6
+ console.log(`Kaelum CLI
7
+ Usage:
8
+ kaelum create # interactive
9
+ kaelum create <name> # create using interactive template choice
10
+ kaelum create <name> --template web|api # non-interactive (name provided, template preselected)
11
+ kaelum help
12
+ `);
13
+ }
14
+
15
+ async function main() {
16
+ const [command, maybeName, maybeFlag, maybeTemplate] = argv;
17
+
18
+ if (
19
+ !command ||
20
+ command === "help" ||
21
+ command === "--help" ||
22
+ command === "-h"
23
+ ) {
24
+ printHelp();
25
+ return;
26
+ }
27
+
28
+ if (command === "create") {
29
+ // non-interactive shorthand: kaelum create my-app --template web
30
+ if (maybeName && maybeFlag === "--template" && maybeTemplate) {
31
+ await createProject({ projectName: maybeName, template: maybeTemplate });
32
+ return;
33
+ }
34
+
35
+ // non-interactive shorthand: kaelum create my-app (will still ask template)
36
+ if (maybeName && !maybeFlag) {
37
+ await createProject({ projectName: maybeName });
38
+ return;
39
+ }
40
+
41
+ // otherwise interactive flow
42
+ await createProject();
43
+ return;
44
+ }
5
45
 
6
- if (command === 'create') {
7
- createProject();
8
- } else {
9
46
  console.log(`Comando nรฃo reconhecido: ${command}`);
10
- console.log(`Use: kaelum create`);
47
+ printHelp();
11
48
  }
49
+
50
+ main().catch((err) => {
51
+ console.error("Error running Kaelum CLI:", err);
52
+ process.exit(1);
53
+ });
@@ -1,12 +1,26 @@
1
+ // app.js - example API project generated by Kaelum (API template)
1
2
  const kaelum = require("kaelum");
3
+
2
4
  const app = kaelum();
3
5
 
6
+ // enable basic safety + logs via setConfig
4
7
  app.setConfig({
5
8
  cors: true,
6
- helmet: true
9
+ helmet: true,
10
+ logs: true, // uses morgan internally
11
+ bodyParser: true,
7
12
  });
8
13
 
14
+ // mount routes
9
15
  const routes = require("./routes");
10
16
  routes(app);
11
17
 
12
- app.start(3000);
18
+ // health check
19
+ app.healthCheck("/health");
20
+
21
+ // use Kaelum generic error handler (JSON responses)
22
+ app.useErrorHandler({ exposeStack: false });
23
+
24
+ // start server
25
+ const PORT = process.env.PORT || 4000;
26
+ app.start(PORT);
@@ -0,0 +1,58 @@
1
+ // controllers/usersController.js
2
+ // Simple in-memory users controller for demonstration.
3
+
4
+ let _id = 1;
5
+ const users = [
6
+ { id: _id++, name: "Alice", email: "alice@example.com" },
7
+ { id: _id++, name: "Bob", email: "bob@example.com" },
8
+ ];
9
+
10
+ function getUsers(req, res) {
11
+ res.json({ data: users });
12
+ }
13
+
14
+ function createUser(req, res) {
15
+ const body = req.body || {};
16
+ if (!body.name || !body.email) {
17
+ return res
18
+ .status(400)
19
+ .json({ error: { message: "name and email required" } });
20
+ }
21
+ const user = { id: _id++, name: body.name, email: body.email };
22
+ users.push(user);
23
+ res.status(201).json({ data: user });
24
+ }
25
+
26
+ function getUserById(req, res) {
27
+ const id = Number(req.params.id);
28
+ const u = users.find((x) => x.id === id);
29
+ if (!u) return res.status(404).json({ error: { message: "User not found" } });
30
+ res.json({ data: u });
31
+ }
32
+
33
+ function updateUser(req, res) {
34
+ const id = Number(req.params.id);
35
+ const u = users.find((x) => x.id === id);
36
+ if (!u) return res.status(404).json({ error: { message: "User not found" } });
37
+ const body = req.body || {};
38
+ if (body.name) u.name = body.name;
39
+ if (body.email) u.email = body.email;
40
+ res.json({ data: u });
41
+ }
42
+
43
+ function deleteUser(req, res) {
44
+ const id = Number(req.params.id);
45
+ const idx = users.findIndex((x) => x.id === id);
46
+ if (idx === -1)
47
+ return res.status(404).json({ error: { message: "User not found" } });
48
+ const removed = users.splice(idx, 1)[0];
49
+ res.json({ data: removed });
50
+ }
51
+
52
+ module.exports = {
53
+ getUsers,
54
+ createUser,
55
+ getUserById,
56
+ updateUser,
57
+ deleteUser,
58
+ };
@@ -0,0 +1,13 @@
1
+ // middlewares/authMock.js
2
+ // Simple mock "authentication" middleware for demo purposes.
3
+ // Checks for header "x-api-key: secret" โ€” if absent, returns 401.
4
+
5
+ module.exports = function (req, res, next) {
6
+ const key = req.headers["x-api-key"] || req.query.api_key;
7
+ if (!key || key !== "secret") {
8
+ return res
9
+ .status(401)
10
+ .json({ error: { message: "Unauthorized. Provide x-api-key: secret" } });
11
+ }
12
+ next();
13
+ };
@@ -1,17 +1,24 @@
1
1
  {
2
2
  "name": "kaelum-api-app",
3
- "version": "1.0.0",
4
- "description": "A basic API template generated by Kaelum.",
5
- "main": "app.js",
3
+ "version": "0.1.0",
4
+ "description": "Exemplo de app API gerado pela CLI Kaelum",
6
5
  "scripts": {
7
6
  "start": "node app.js",
8
7
  "dev": "nodemon app.js"
9
8
  },
9
+ "keywords": [
10
+ "kaelum",
11
+ "api"
12
+ ],
13
+ "author": "",
14
+ "license": "MIT",
10
15
  "dependencies": {
11
- "kaelum": "1.1.0"
16
+ "kaelum": "^1.3.0",
17
+ "cors": "^2.8.5",
18
+ "helmet": "^6.0.0",
19
+ "morgan": "^1.10.0"
12
20
  },
13
21
  "devDependencies": {
14
22
  "nodemon": "^2.0.22"
15
- },
16
- "type": "commonjs"
17
- }
23
+ }
24
+ }
@@ -1,11 +1,34 @@
1
- const userController = require("./controllers/userController");
2
- const logger = require("./middlewares/logger");
1
+ // routes.js - registers API endpoints using app.apiRoute
2
+ const {
3
+ getUsers,
4
+ createUser,
5
+ getUserById,
6
+ updateUser,
7
+ deleteUser,
8
+ } = require("./controllers/usersController");
3
9
 
4
- function Routes(app) {
5
- app.addRoute("/users", {
6
- get: [logger, userController.getUsers],
7
- post: [logger, userController.createUser],
10
+ const auth = require("./middlewares/authMock");
11
+
12
+ module.exports = function (app) {
13
+ // Global example: apply auth middleware on /users POST (create)
14
+ // also demonstrate per-path middleware usage via setMiddleware(path, middleware)
15
+ app.setMiddleware("/users", (req, res, next) => {
16
+ // a small wrapper to demonstrate both setMiddleware signature and route-level control
17
+ // allow GET without auth, require auth for POST/PUT/DELETE by checking method
18
+ if (["POST", "PUT", "DELETE"].includes(req.method)) {
19
+ return require("./middlewares/authMock")(req, res, next);
20
+ }
21
+ next();
8
22
  });
9
- }
10
23
 
11
- module.exports = Routes;
24
+ // Resource routes using apiRoute
25
+ app.apiRoute("users", {
26
+ get: getUsers,
27
+ post: createUser,
28
+ "/:id": {
29
+ get: getUserById,
30
+ put: updateUser,
31
+ delete: deleteUser,
32
+ },
33
+ });
34
+ };