rad-api 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 +156 -0
- package/index.js +36 -0
- package/package.json +28 -0
- package/src/commands/generate.js +44 -0
- package/src/templates/controller.template.js +31 -0
- package/src/templates/route.template.js +23 -0
- package/src/utils/fileHelper.js +42 -0
- package/src/utils/parser.js +24 -0
- package/src/utils/stringHelper.js +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# KAPI - Rapid API Development Tool
|
|
2
|
+
|
|
3
|
+
Un outil puissant pour générer rapidement des fichiers de routes, contrôleurs et modèles pour votre API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g rad-api
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Ou pour le développement local :
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm link
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Utilisation
|
|
18
|
+
|
|
19
|
+
### Générer une route
|
|
20
|
+
|
|
21
|
+
Générez un fichier de route complet pour une table spécifique :
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
kapi generate route <tableName>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
#### Exemple :
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
kapi generate route citations
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Cela créera un fichier `citations.routes.js` avec :
|
|
34
|
+
- Configuration Prisma MariaDB
|
|
35
|
+
- Fonction `all()` pour récupérer tous les enregistrements
|
|
36
|
+
- Gestion des erreurs complète
|
|
37
|
+
- Logs de requête
|
|
38
|
+
|
|
39
|
+
#### Fichier généré (`citations.routes.js`) :
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
import { PrismaMariaDb } from '@prisma/adapter-mariadb';
|
|
43
|
+
import { PrismaClient } from '../../../generated/prisma/client.js';
|
|
44
|
+
|
|
45
|
+
const maria = new PrismaMariaDb({
|
|
46
|
+
host: process.env.DATABASE_HOST,
|
|
47
|
+
port: process.env.DATABASE_PORT,
|
|
48
|
+
user: process.env.DATABASE_USER,
|
|
49
|
+
password: process.env.DATABASE_PASSWORD,
|
|
50
|
+
database: process.env.DATABASE_NAME
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const prisma = new PrismaClient({ adapter: maria });
|
|
54
|
+
|
|
55
|
+
export const all = async (req, res) => {
|
|
56
|
+
req.log?.info('all Citations endpoint');
|
|
57
|
+
try {
|
|
58
|
+
const allCitation = await main();
|
|
59
|
+
res.status(200);
|
|
60
|
+
res.json(allCitation);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
req.log?.error('Error fetching Citations:', error);
|
|
63
|
+
return res.status(500).json({ msg: 'Internal Server Error' });
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
async function main() {
|
|
68
|
+
const allCitation = await prisma.Citations.findMany()
|
|
69
|
+
console.log('All Citations:', JSON.stringify(allCitation, null, 2))
|
|
70
|
+
return allCitation;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Fonctionnalités
|
|
75
|
+
|
|
76
|
+
- ✅ Génération automatique de fichiers de routes
|
|
77
|
+
- ✅ Conversion intelligente des noms (singulier/pluriel, PascalCase)
|
|
78
|
+
- ✅ Intégration Prisma MariaDB préinstallée
|
|
79
|
+
- ✅ Gestion des erreurs et logs
|
|
80
|
+
- ✅ Protection contre les fichiers dupliqués
|
|
81
|
+
- ✅ Messages de sortie détaillés et utiles
|
|
82
|
+
|
|
83
|
+
## Structure du projet
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
RAD-api/
|
|
87
|
+
├── index.js # Point d'entrée CLI
|
|
88
|
+
├── package.json
|
|
89
|
+
├── README.md
|
|
90
|
+
└── src/
|
|
91
|
+
├── commands/
|
|
92
|
+
│ └── generate.js # Logique de génération
|
|
93
|
+
├── templates/
|
|
94
|
+
│ └── route.template.js # Template de route
|
|
95
|
+
└── utils/
|
|
96
|
+
├── parser.js # Parser d'arguments
|
|
97
|
+
├── fileHelper.js # Utilitaires de fichier
|
|
98
|
+
└── stringHelper.js # Utilitaires de chaîne
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Options d'environnement
|
|
102
|
+
|
|
103
|
+
Le fichier généré utilise les variables d'environnement suivantes :
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
DATABASE_HOST = Adresse du serveur MariaDB
|
|
107
|
+
DATABASE_PORT = Port MariaDB (par défaut: 3306)
|
|
108
|
+
DATABASE_USER = Utilisateur MariaDB
|
|
109
|
+
DATABASE_PASSWORD = Mot de passe MariaDB
|
|
110
|
+
DATABASE_NAME = Nom de la base de données
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Exemples d'utilisation
|
|
114
|
+
|
|
115
|
+
### Tables simples
|
|
116
|
+
```bash
|
|
117
|
+
kapi generate route products
|
|
118
|
+
kapi generate route categories
|
|
119
|
+
kapi generate route customers
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Tables plurielles
|
|
123
|
+
```bash
|
|
124
|
+
kapi generate route citations # Génère handlers pour la table "Citations"
|
|
125
|
+
kapi generate route users # Génère handlers pour la table "Users"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Gestion des erreurs
|
|
129
|
+
|
|
130
|
+
L'outil gère automatiquement :
|
|
131
|
+
- Les fichiers déjà existants ✓
|
|
132
|
+
- Les noms de table vides ✓
|
|
133
|
+
- Les répertoires manquants (création automatique) ✓
|
|
134
|
+
|
|
135
|
+
## Développement
|
|
136
|
+
|
|
137
|
+
Pour ajouter de nouvelles commandes :
|
|
138
|
+
|
|
139
|
+
1. Créez un template dans `src/templates/`
|
|
140
|
+
2. Créez un fichier de commande dans `src/commands/`
|
|
141
|
+
3. Ajoutez la logique de parsing dans `index.js`
|
|
142
|
+
|
|
143
|
+
## Améliorations futures
|
|
144
|
+
|
|
145
|
+
- [ ] `kapi generate controller <tableName>` - Générer les contrôleurs
|
|
146
|
+
- [ ] `kapi generate model <tableName>` - Générer les modèles Prisma
|
|
147
|
+
- [ ] `kapi generate crud <tableName>` - Générer CRUD complet
|
|
148
|
+
- [ ] `kapi config` - Configuration interactive
|
|
149
|
+
|
|
150
|
+
## Licence
|
|
151
|
+
|
|
152
|
+
ISC
|
|
153
|
+
|
|
154
|
+
## Auteur
|
|
155
|
+
|
|
156
|
+
kferrandon
|
package/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from './src/utils/parser.js';
|
|
4
|
+
import { generate } from './src/commands/generate.js';
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
const args = parseArgs(process.argv.slice(2));
|
|
8
|
+
console.log(args);
|
|
9
|
+
try {
|
|
10
|
+
if (args.command === 'generate') {
|
|
11
|
+
if (!args.table) {
|
|
12
|
+
console.error('❌ Error: Table name is required');
|
|
13
|
+
console.log('Usage: kapi generate route <tableName>');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
if (args.type) {
|
|
17
|
+
await generate(args.type, args.table, args.path);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.log('🔧 KAPI - Rapid API Development');
|
|
23
|
+
console.log('\nUsage:');
|
|
24
|
+
console.log(' kapi generate route <tableName> - Generate a route file for a table');
|
|
25
|
+
console.log(' kapi generate controller <tableName> - Generate a controller file for a table');
|
|
26
|
+
console.log('\nExamples:');
|
|
27
|
+
console.log(' kapi generate route citations');
|
|
28
|
+
console.log(' kapi generate route users');
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('❌ Error:', error.message);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rad-api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "RAD pour créer des routes, controller, model ... etc",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"kapi": "index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/kferrandonFulbert/rad-api.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"RAD",
|
|
19
|
+
"API",
|
|
20
|
+
"automation"
|
|
21
|
+
],
|
|
22
|
+
"author": "kferrandon",
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/kferrandonFulbert/rad-api/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/kferrandonFulbert/rad-api#readme"
|
|
28
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readTemplate, writeFile, getOutputPath, fileExists } from '../utils/fileHelper.js';
|
|
2
|
+
import { formatTableName } from '../utils/stringHelper.js';
|
|
3
|
+
|
|
4
|
+
export async function generate(type, tableName, pathOverride='output') {
|
|
5
|
+
try {
|
|
6
|
+
// Valider le nom de la table
|
|
7
|
+
if (!tableName || tableName.trim() === '') {
|
|
8
|
+
throw new Error('Table name cannot be empty');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Formater les noms
|
|
12
|
+
const { tableSingular, tablePlural } = formatTableName(tableName);
|
|
13
|
+
|
|
14
|
+
// Récupérer le template
|
|
15
|
+
let content = readTemplate('route');
|
|
16
|
+
|
|
17
|
+
// Remplacer les placeholders
|
|
18
|
+
content = content.replace(/{{TABLE_SINGULAR}}/g, tableSingular);
|
|
19
|
+
content = content.replace(/{{TABLE_PLURAL}}/g, tablePlural);
|
|
20
|
+
|
|
21
|
+
// Déterminer le chemin de sortie
|
|
22
|
+
const outputPath = getOutputPath(tableName, type, pathOverride);
|
|
23
|
+
|
|
24
|
+
// Vérifier si le fichier existe déjà
|
|
25
|
+
if (fileExists(outputPath)) {
|
|
26
|
+
throw new Error(`File ${tableName}.${type}s.js already exists. Please choose a different name or remove the existing file.`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Écrire le fichier
|
|
30
|
+
writeFile(outputPath, content);
|
|
31
|
+
|
|
32
|
+
console.log(`✅ ${type} file created successfully!`);
|
|
33
|
+
console.log(`📁 Location: ${outputPath}`);
|
|
34
|
+
console.log(`\n📝 File content generated for table: ${tablePlural}`);
|
|
35
|
+
console.log(` - Handler: all() - Get all ${tablePlural}`);
|
|
36
|
+
console.log(`\n🚀 Next steps:`);
|
|
37
|
+
console.log(` 1. Import this route in your main ${type}`);
|
|
38
|
+
console.log(` 2. Ensure your Prisma client is properly configured`);
|
|
39
|
+
console.log(` 3. Update the adapter path if needed: ../../../generated/prisma/client.js`);
|
|
40
|
+
|
|
41
|
+
} catch (error) {
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PrismaMariaDb } from '@prisma/adapter-mariadb';
|
|
2
|
+
import { PrismaClient } from '../../../generated/prisma/client.js';
|
|
3
|
+
|
|
4
|
+
const maria = new PrismaMariaDb({
|
|
5
|
+
host: process.env.DATABASE_HOST,
|
|
6
|
+
port: process.env.DATABASE_PORT,
|
|
7
|
+
user: process.env.DATABASE_USER,
|
|
8
|
+
password: process.env.DATABASE_PASSWORD,
|
|
9
|
+
database: process.env.DATABASE_NAME
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const prisma = new PrismaClient({ adapter: maria });
|
|
13
|
+
|
|
14
|
+
export const all = async (req, res) => {
|
|
15
|
+
req.log?.info('all {{TABLE_PLURAL}} endpoint');
|
|
16
|
+
try {
|
|
17
|
+
const all{{TABLE_SINGULAR}} = await main();
|
|
18
|
+
|
|
19
|
+
res.status(200);
|
|
20
|
+
res.json(all{{TABLE_SINGULAR}});
|
|
21
|
+
} catch (error) {
|
|
22
|
+
req.log?.error('Error fetching {{TABLE_PLURAL}}:', error);
|
|
23
|
+
return res.status(500).json({ msg: 'Internal Server Error' });
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
async function main() {
|
|
28
|
+
const all{{TABLE_SINGULAR}} = await prisma.{{TABLE_PLURAL}}.findMany()
|
|
29
|
+
console.log('All {{TABLE_PLURAL}}:', JSON.stringify(all{{TABLE_SINGULAR}}, null, 2))
|
|
30
|
+
return all{{TABLE_SINGULAR}};
|
|
31
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { all } from '../controllers/citations.controller.js';
|
|
3
|
+
import { authMiddleware } from '../middlewares/auth.middleware.js';
|
|
4
|
+
|
|
5
|
+
const router = Router();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @openapi
|
|
9
|
+
* /{TABLE_SINGULAR}/:
|
|
10
|
+
* get:
|
|
11
|
+
* summary: get all {TABLE_PLURAL}
|
|
12
|
+
* responses:
|
|
13
|
+
* 200:
|
|
14
|
+
* description: OK
|
|
15
|
+
* content:
|
|
16
|
+
* application/json:
|
|
17
|
+
* schema:
|
|
18
|
+
* type: object
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
router.get('/', all);
|
|
22
|
+
|
|
23
|
+
export default router;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
export function getOutputPath(tableName, type = 'route', pathOverride = 'output') {
|
|
9
|
+
// Le fichier sera créé dans le répertoire output
|
|
10
|
+
let cwd =null;
|
|
11
|
+
if (pathOverride === 'output') {
|
|
12
|
+
cwd = process.cwd() + "/" + pathOverride;
|
|
13
|
+
} else {
|
|
14
|
+
cwd = pathOverride;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return path.join(cwd, `${tableName}.${type}.js`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function fileExists(filePath) {
|
|
21
|
+
return fs.existsSync(filePath);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function writeFile(filePath, content) {
|
|
25
|
+
const dir = path.dirname(filePath);
|
|
26
|
+
|
|
27
|
+
// Créer le répertoire s'il n'existe pas
|
|
28
|
+
if (!fs.existsSync(dir)) {
|
|
29
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getTemplatePath(templateName) {
|
|
36
|
+
return path.join(__dirname, '..', 'templates', `${templateName}.template.js`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function readTemplate(templateName) {
|
|
40
|
+
const templatePath = getTemplatePath(templateName);
|
|
41
|
+
return fs.readFileSync(templatePath, 'utf-8');
|
|
42
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function parseArgs(args) {
|
|
2
|
+
const result = {
|
|
3
|
+
command: null,
|
|
4
|
+
type: null,
|
|
5
|
+
table: null,
|
|
6
|
+
path: 'output'
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
if (args.length === 0) return result;
|
|
10
|
+
|
|
11
|
+
result.command = args[0]; // 'generate'
|
|
12
|
+
|
|
13
|
+
if (args.length > 1) {
|
|
14
|
+
result.type = args[1]; // 'route'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (args.length > 2) {
|
|
18
|
+
result.table = args[2]; // 'citations'
|
|
19
|
+
}
|
|
20
|
+
if (args.length > 3) {
|
|
21
|
+
result.path = args[3]; // 'path'
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function capitalize(str) {
|
|
2
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function singularize(word) {
|
|
6
|
+
// Règles simples de singularisation pour le français/anglais
|
|
7
|
+
if (word.endsWith('ies')) {
|
|
8
|
+
return word.slice(0, -3) + 'y';
|
|
9
|
+
}
|
|
10
|
+
if (word.endsWith('es')) {
|
|
11
|
+
return word.slice(0, -2);
|
|
12
|
+
}
|
|
13
|
+
if (word.endsWith('s')) {
|
|
14
|
+
return word.slice(0, -1);
|
|
15
|
+
}
|
|
16
|
+
return word;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function toPascalCase(str) {
|
|
20
|
+
return str
|
|
21
|
+
.split(/[-_]/)
|
|
22
|
+
.map(word => capitalize(word))
|
|
23
|
+
.join('');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function formatTableName(tableName) {
|
|
27
|
+
const plural = tableName.toLowerCase();
|
|
28
|
+
const singular = toPascalCase(singularize(tableName));
|
|
29
|
+
const pluralPascal = toPascalCase(tableName);
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
tableName: plural,
|
|
33
|
+
tableSingular: singular,
|
|
34
|
+
tablePlural: pluralPascal
|
|
35
|
+
};
|
|
36
|
+
}
|