cleancode-e 1.0.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 +181 -0
- package/bin/index.js +2 -0
- package/package.json +15 -0
- package/src/cli.js +159 -0
- package/src/templates/.env.example +10 -0
- package/src/templates/app.mongo.js +18 -0
- package/src/templates/app.mysql.js +21 -0
- package/src/templates/app.none.js +16 -0
- package/src/templates/config/db.mongo.js +6 -0
- package/src/templates/config/db.mysql.js +14 -0
- package/src/templates/config/readme.txt +4 -0
- package/src/templates/controllers/example.userController.mongo.js +11 -0
- package/src/templates/controllers/example.userController.mysql.js +11 -0
- package/src/templates/controllers/example.userController.none.js +12 -0
- package/src/templates/controllers/readme.txt +4 -0
- package/src/templates/middleware/example.authMiddleware.js +9 -0
- package/src/templates/middleware/readme.txt +5 -0
- package/src/templates/models/example.userModel.mongo.js +9 -0
- package/src/templates/models/example.userModel.mysql.js +12 -0
- package/src/templates/models/readme.txt +4 -0
- package/src/templates/plugins/example.corsPlugin.js +8 -0
- package/src/templates/plugins/readme.txt +5 -0
- package/src/templates/routes/example.userRoute.js +6 -0
- package/src/templates/routes/readme.txt +4 -0
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ⚡ cleancode-e
|
|
4
|
+
|
|
5
|
+
**CLI Generator untuk project backend Fastify — siap pakai dalam hitungan detik.**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/cleancode-e)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://nodejs.org)
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Apa itu cleancode-e?
|
|
16
|
+
|
|
17
|
+
`cleancode-e` adalah CLI generator yang men-scaffold project backend [Fastify](https://fastify.dev) secara interaktif — lengkap dengan struktur folder siap produksi, pilihan database (MongoDB / MySQL / tanpa database), dan auto-install dependency.
|
|
18
|
+
|
|
19
|
+
Terinspirasi dari Artisan (Laravel) dan Create-React-App, tapi untuk ekosistem **Node.js + Fastify**.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quickstart
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx cleancode-e
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> Tidak perlu install dulu. Jalankan langsung, ikuti promptnya.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Cara Pakai
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx cleancode-e
|
|
37
|
+
|
|
38
|
+
# atau jika install global:
|
|
39
|
+
npm install -g cleancode-e
|
|
40
|
+
cleancode-e
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Ikuti prompt interaktifnya:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
┌ cleancode-e CLI Generator
|
|
47
|
+
│
|
|
48
|
+
◇ Nama project kamu:
|
|
49
|
+
│ my-api
|
|
50
|
+
│
|
|
51
|
+
◇ Pilih database:
|
|
52
|
+
│ ● Tidak pakai database (in-memory)
|
|
53
|
+
│ ○ MongoDB (Mongoose)
|
|
54
|
+
│ ○ MySQL (Sequelize + mysql2)
|
|
55
|
+
│
|
|
56
|
+
◇ Pakai nodemon untuk auto-reload saat development?
|
|
57
|
+
│ ● Ya ○ Tidak
|
|
58
|
+
│
|
|
59
|
+
└ folder berhasil dibuat, Selamat berkarya! masbro 🚀
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Struktur Project yang Dihasilkan
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
my-api/
|
|
68
|
+
├── app.js # Entry point server Fastify
|
|
69
|
+
├── package.json # Scripts & dependencies
|
|
70
|
+
├── .env.example # Template environment variables
|
|
71
|
+
│
|
|
72
|
+
├── routes/
|
|
73
|
+
│ ├── example.userRoute.js # Contoh route GET & POST /users
|
|
74
|
+
│ └── readme.txt # Panduan penggunaan folder routes
|
|
75
|
+
│
|
|
76
|
+
├── controllers/
|
|
77
|
+
│ ├── example.userController.js # Contoh logic controller
|
|
78
|
+
│ └── readme.txt
|
|
79
|
+
│
|
|
80
|
+
├── models/
|
|
81
|
+
│ ├── example.userModel.js # Skema User (Mongoose / Sequelize)
|
|
82
|
+
│ └── readme.txt
|
|
83
|
+
│
|
|
84
|
+
├── config/
|
|
85
|
+
│ ├── db.js # Koneksi database (jika dipilih)
|
|
86
|
+
│ └── readme.txt
|
|
87
|
+
│
|
|
88
|
+
├── plugins/
|
|
89
|
+
│ ├── example.corsPlugin.js # Contoh plugin CORS
|
|
90
|
+
│ └── readme.txt
|
|
91
|
+
│
|
|
92
|
+
└── middleware/
|
|
93
|
+
├── example.authMiddleware.js # Contoh middleware autentikasi
|
|
94
|
+
└── readme.txt
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Dependency yang Diinstall Otomatis
|
|
100
|
+
|
|
101
|
+
| Pilihan | Package yang diinstall |
|
|
102
|
+
|---|---|
|
|
103
|
+
| Semua project | `fastify` |
|
|
104
|
+
| MongoDB | + `mongoose` |
|
|
105
|
+
| MySQL | + `sequelize`, `mysql2` |
|
|
106
|
+
| Nodemon (jika Ya) | `nodemon` (devDependency) |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Setup Setelah Generate
|
|
111
|
+
|
|
112
|
+
### 1. Tanpa Database
|
|
113
|
+
Langsung jalankan:
|
|
114
|
+
```bash
|
|
115
|
+
cd my-api
|
|
116
|
+
npm start
|
|
117
|
+
# → http://localhost:3000
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 2. MongoDB
|
|
121
|
+
```bash
|
|
122
|
+
cd my-api
|
|
123
|
+
|
|
124
|
+
# Rename dan isi .env
|
|
125
|
+
cp .env.example .env
|
|
126
|
+
# Edit MONGO_URI di .env:
|
|
127
|
+
# MONGO_URI=mongodb://localhost:27017/my-api
|
|
128
|
+
# atau MongoDB Atlas:
|
|
129
|
+
# MONGO_URI=mongodb+srv://user:pass@cluster.mongodb.net/my-api
|
|
130
|
+
|
|
131
|
+
npm start
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 3. MySQL
|
|
135
|
+
```bash
|
|
136
|
+
cd my-api
|
|
137
|
+
|
|
138
|
+
# Buat database dulu di MySQL:
|
|
139
|
+
# CREATE DATABASE my_api;
|
|
140
|
+
|
|
141
|
+
cp .env.example .env
|
|
142
|
+
# Edit .env:
|
|
143
|
+
# DB_HOST=localhost
|
|
144
|
+
# DB_NAME=my_api
|
|
145
|
+
# DB_USER=root
|
|
146
|
+
# DB_PASS=yourpassword
|
|
147
|
+
|
|
148
|
+
npm start
|
|
149
|
+
# Sequelize akan auto-sync tabel saat pertama kali jalan
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Scripts
|
|
155
|
+
|
|
156
|
+
| Command | Keterangan |
|
|
157
|
+
|---|---|
|
|
158
|
+
| `npm start` | Jalankan server (production) |
|
|
159
|
+
| `npm run dev` | Jalankan dengan nodemon (development) |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Syarat
|
|
164
|
+
|
|
165
|
+
- Node.js `>= 18`
|
|
166
|
+
- npm `>= 8`
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Tech Stack
|
|
171
|
+
|
|
172
|
+
- **[Fastify](https://fastify.dev)** — Web framework Node.js ultra-cepat
|
|
173
|
+
- **[@clack/prompts](https://github.com/natemoo-re/clack)** — Prompt CLI yang elegan
|
|
174
|
+
- **[execa](https://github.com/sindresorhus/execa)** — Shell command runner
|
|
175
|
+
- **[picocolors](https://github.com/alexeyraspopov/picocolors)** — Terminal color output
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Lisensi
|
|
180
|
+
|
|
181
|
+
MIT © cleancode-e contributors
|
package/bin/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cleancode-e",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI generator untuk project backend Fastify siap pakai",
|
|
5
|
+
"keywords": ["fastify", "cli", "generator", "scaffold", "backend", "nodejs"],
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"cleancode-e": "./bin/index.js"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@clack/prompts": "^0.7.0",
|
|
12
|
+
"execa": "^8.0.1",
|
|
13
|
+
"picocolors": "^1.0.0"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { intro, outro, text, select, confirm, spinner, note } from "@clack/prompts";
|
|
2
|
+
import { execa } from "execa";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import colors from "picocolors";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
async function main() {
|
|
12
|
+
console.clear();
|
|
13
|
+
intro(colors.bgCyan(colors.black(" cleancode-e CLI Generator ")));
|
|
14
|
+
|
|
15
|
+
const projectName = await text({
|
|
16
|
+
message: "Nama project kamu:",
|
|
17
|
+
placeholder: "contoh: my-api",
|
|
18
|
+
validate: (value) => {
|
|
19
|
+
if (!value) return "Nama project tidak boleh kosong";
|
|
20
|
+
if (value.includes(" ")) return "Nama project tidak boleh mengandung spasi";
|
|
21
|
+
if (value.length < 3) return "Nama project minimal 3 karakter";
|
|
22
|
+
if (/\d/.test(value)) return "Nama project tidak boleh mengandung angka";
|
|
23
|
+
if (fs.existsSync(value)) return "Folder dengan nama itu sudah ada";
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (typeof projectName === "symbol") {
|
|
28
|
+
outro(colors.red("Dibatalkan."));
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const database = await select({
|
|
33
|
+
message: "Pilih database:",
|
|
34
|
+
options: [
|
|
35
|
+
{ value: "none", label: "Tidak pakai database (in-memory)" },
|
|
36
|
+
{ value: "mongo", label: "MongoDB (Mongoose)" },
|
|
37
|
+
{ value: "mysql", label: "MySQL (Sequelize + mysql2)" },
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (typeof database === "symbol") {
|
|
42
|
+
outro(colors.red("Dibatalkan."));
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const useNodemon = await confirm({
|
|
47
|
+
message: "Pakai nodemon untuk auto-reload saat development?",
|
|
48
|
+
initialValue: true,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (typeof useNodemon === "symbol") {
|
|
52
|
+
outro(colors.red("Dibatalkan."));
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const targetDir = path.resolve(projectName);
|
|
57
|
+
const templateDir = path.join(__dirname, "templates");
|
|
58
|
+
|
|
59
|
+
const s = spinner();
|
|
60
|
+
s.start("Menyiapkan struktur project...");
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const dirs = ["routes", "controllers", "models", "config", "plugins", "middleware"];
|
|
64
|
+
for (const dir of dirs) {
|
|
65
|
+
fs.mkdirSync(path.join(targetDir, dir), { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const from = (src) => path.join(templateDir, src);
|
|
69
|
+
const to = (dest) => path.join(targetDir, dest);
|
|
70
|
+
const cp = (src, dest) => fs.copyFileSync(from(src), to(dest));
|
|
71
|
+
|
|
72
|
+
cp(`app.${database}.js`, "app.js");
|
|
73
|
+
cp(".env.example", ".env.example");
|
|
74
|
+
|
|
75
|
+
cp("routes/example.userRoute.js", "routes/example.userRoute.js");
|
|
76
|
+
cp("routes/readme.txt", "routes/readme.txt");
|
|
77
|
+
cp("controllers/readme.txt", "controllers/readme.txt");
|
|
78
|
+
cp("models/readme.txt", "models/readme.txt");
|
|
79
|
+
cp("config/readme.txt", "config/readme.txt");
|
|
80
|
+
cp("plugins/readme.txt", "plugins/readme.txt");
|
|
81
|
+
cp("plugins/example.corsPlugin.js", "plugins/example.corsPlugin.js");
|
|
82
|
+
cp("middleware/readme.txt", "middleware/readme.txt");
|
|
83
|
+
cp("middleware/example.authMiddleware.js", "middleware/example.authMiddleware.js");
|
|
84
|
+
|
|
85
|
+
if (database === "mongo") {
|
|
86
|
+
cp("config/db.mongo.js", "config/db.js");
|
|
87
|
+
cp("models/example.userModel.mongo.js", "models/example.userModel.js");
|
|
88
|
+
cp("controllers/example.userController.mongo.js", "controllers/example.userController.js");
|
|
89
|
+
} else if (database === "mysql") {
|
|
90
|
+
cp("config/db.mysql.js", "config/db.js");
|
|
91
|
+
cp("models/example.userModel.mysql.js", "models/example.userModel.js");
|
|
92
|
+
cp("controllers/example.userController.mysql.js", "controllers/example.userController.js");
|
|
93
|
+
} else {
|
|
94
|
+
cp("controllers/example.userController.none.js", "controllers/example.userController.js");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const deps = { fastify: "latest" };
|
|
98
|
+
if (database === "mongo") deps.mongoose = "latest";
|
|
99
|
+
if (database === "mysql") {
|
|
100
|
+
deps.sequelize = "latest";
|
|
101
|
+
deps.mysql2 = "latest";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fs.writeFileSync(
|
|
105
|
+
to("package.json"),
|
|
106
|
+
JSON.stringify({
|
|
107
|
+
name: projectName,
|
|
108
|
+
version: "1.0.0",
|
|
109
|
+
type: "module",
|
|
110
|
+
main: "app.js",
|
|
111
|
+
scripts: {
|
|
112
|
+
start: "node app.js",
|
|
113
|
+
dev: useNodemon ? "nodemon app.js" : "node --watch app.js",
|
|
114
|
+
},
|
|
115
|
+
dependencies: deps,
|
|
116
|
+
}, null, 2)
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
s.stop("Struktur project berhasil dibuat!");
|
|
120
|
+
|
|
121
|
+
const installSpinner = spinner();
|
|
122
|
+
installSpinner.start("Menginstall dependencies (ini mungkin memakan waktu >_<)...");
|
|
123
|
+
|
|
124
|
+
const installList = ["fastify"];
|
|
125
|
+
if (database === "mongo") installList.push("mongoose");
|
|
126
|
+
if (database === "mysql") installList.push("sequelize", "mysql2");
|
|
127
|
+
|
|
128
|
+
await execa("npm", ["install", ...installList], { cwd: targetDir });
|
|
129
|
+
|
|
130
|
+
if (useNodemon) {
|
|
131
|
+
await execa("npm", ["install", "--save-dev", "nodemon"], { cwd: targetDir });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
installSpinner.stop("Dependencies berhasil diinstall!");
|
|
135
|
+
|
|
136
|
+
note(
|
|
137
|
+
[
|
|
138
|
+
`Project berhasil dibuat di: ${colors.cyan(targetDir)}`,
|
|
139
|
+
"",
|
|
140
|
+
` cd ${projectName}`,
|
|
141
|
+
` npm start`,
|
|
142
|
+
"",
|
|
143
|
+
database !== "none"
|
|
144
|
+
? `Isi ${colors.yellow(".env.example")} lalu rename jadi ${colors.yellow(".env")}`
|
|
145
|
+
: "",
|
|
146
|
+
].filter(Boolean).join("\n"),
|
|
147
|
+
"Selesai!"
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
outro(colors.green("folder berhasil dibuat, Selamat berkarya! masbro 🚀"));
|
|
151
|
+
} catch (err) {
|
|
152
|
+
s.stop(colors.red("Terjadi kesalahan!"));
|
|
153
|
+
console.error(err);
|
|
154
|
+
outro(colors.red("Proses pembuatan project gagal."));
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
main();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Fastify from 'fastify';
|
|
2
|
+
import { connectDB } from './config/db.js';
|
|
3
|
+
import userRoutes from './routes/userRoutes.js';
|
|
4
|
+
|
|
5
|
+
const fastify = Fastify({ logger: true });
|
|
6
|
+
|
|
7
|
+
fastify.register(userRoutes);
|
|
8
|
+
|
|
9
|
+
const start = async () => {
|
|
10
|
+
try {
|
|
11
|
+
await connectDB();
|
|
12
|
+
await fastify.listen({ port: process.env.PORT || 3000, host: '0.0.0.0' });
|
|
13
|
+
} catch (err) {
|
|
14
|
+
fastify.log.error(err);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
start();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Fastify from 'fastify';
|
|
2
|
+
import sequelize from './config/db.js';
|
|
3
|
+
import userRoutes from './routes/userRoutes.js';
|
|
4
|
+
import './models/User.js';
|
|
5
|
+
|
|
6
|
+
const fastify = Fastify({ logger: true });
|
|
7
|
+
|
|
8
|
+
fastify.register(userRoutes);
|
|
9
|
+
|
|
10
|
+
const start = async () => {
|
|
11
|
+
try {
|
|
12
|
+
await sequelize.authenticate();
|
|
13
|
+
await sequelize.sync();
|
|
14
|
+
console.log('MySQL connected & synced');
|
|
15
|
+
await fastify.listen({ port: process.env.PORT || 3000, host: '0.0.0.0' });
|
|
16
|
+
} catch (err) {
|
|
17
|
+
fastify.log.error(err);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
start();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Fastify from 'fastify';
|
|
2
|
+
import userRoutes from './routes/userRoutes.js';
|
|
3
|
+
|
|
4
|
+
const fastify = Fastify({ logger: true });
|
|
5
|
+
|
|
6
|
+
fastify.register(userRoutes);
|
|
7
|
+
|
|
8
|
+
const start = async () => {
|
|
9
|
+
try {
|
|
10
|
+
await fastify.listen({ port: process.env.PORT || 3000, host: '0.0.0.0' });
|
|
11
|
+
} catch (err) {
|
|
12
|
+
fastify.log.error(err);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
start();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Sequelize } from 'sequelize';
|
|
2
|
+
|
|
3
|
+
const sequelize = new Sequelize(
|
|
4
|
+
process.env.DB_NAME || 'myapp',
|
|
5
|
+
process.env.DB_USER || 'root',
|
|
6
|
+
process.env.DB_PASS || '',
|
|
7
|
+
{
|
|
8
|
+
host: process.env.DB_HOST || 'localhost',
|
|
9
|
+
dialect: 'mysql',
|
|
10
|
+
logging: false,
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export default sequelize;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import User from '../models/example.userModel.js';
|
|
2
|
+
|
|
3
|
+
export async function getUsers(request, reply) {
|
|
4
|
+
const users = await User.find();
|
|
5
|
+
return reply.send({ status: 'success', data: users });
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function createUser(request, reply) {
|
|
9
|
+
const user = await User.create(request.body);
|
|
10
|
+
return reply.code(201).send({ status: 'success', data: user });
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import User from '../models/example.userModel.js';
|
|
2
|
+
|
|
3
|
+
export async function getUsers(request, reply) {
|
|
4
|
+
const users = await User.findAll();
|
|
5
|
+
return reply.send({ status: 'success', data: users });
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function createUser(request, reply) {
|
|
9
|
+
const user = await User.create(request.body);
|
|
10
|
+
return reply.code(201).send({ status: 'success', data: user });
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const users = [];
|
|
2
|
+
|
|
3
|
+
export async function getUsers(request, reply) {
|
|
4
|
+
return reply.send({ status: 'success', data: users });
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export async function createUser(request, reply) {
|
|
8
|
+
const { name, email } = request.body;
|
|
9
|
+
const user = { id: users.length + 1, name, email };
|
|
10
|
+
users.push(user);
|
|
11
|
+
return reply.code(201).send({ status: 'success', data: user });
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export async function authMiddleware(request, reply) {
|
|
2
|
+
const token = request.headers['authorization'];
|
|
3
|
+
if (!token) {
|
|
4
|
+
return reply.code(401).send({ status: 'error', message: 'Unauthorized' });
|
|
5
|
+
}
|
|
6
|
+
// TODO: verifikasi token JWT di sini
|
|
7
|
+
// const decoded = jwt.verify(token.replace('Bearer ', ''), process.env.JWT_SECRET);
|
|
8
|
+
// request.user = decoded;
|
|
9
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
middleware/
|
|
2
|
+
Folder ini berisi fungsi middleware (hook) Fastify.
|
|
3
|
+
Middleware biasanya digunakan untuk autentikasi, logging, dan validasi request.
|
|
4
|
+
Daftarkan sebagai hook di app.js: fastify.addHook('preHandler', myMiddleware)
|
|
5
|
+
Penamaan file: namaMiddleware.middleware.js → contoh: auth.middleware.js
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import mongoose from 'mongoose';
|
|
2
|
+
|
|
3
|
+
const UserSchema = new mongoose.Schema({
|
|
4
|
+
name: { type: String, required: true },
|
|
5
|
+
email: { type: String, required: true, unique: true },
|
|
6
|
+
createdAt: { type: Date, default: Date.now },
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export default mongoose.model('User', UserSchema);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DataTypes } from 'sequelize';
|
|
2
|
+
import sequelize from '../config/db.js';
|
|
3
|
+
|
|
4
|
+
const User = sequelize.define('User', {
|
|
5
|
+
name: { type: DataTypes.STRING, allowNull: false },
|
|
6
|
+
email: { type: DataTypes.STRING, allowNull: false, unique: true },
|
|
7
|
+
}, {
|
|
8
|
+
tableName: 'users',
|
|
9
|
+
timestamps: true,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export default User;
|