@bodheesh/create-bodhi-node-app
Version:
Create a production-ready Node.js REST API with zero configuration
239 lines (201 loc) • 5.88 kB
JavaScript
const fs = require('fs').promises;
const path = require('path');
async function generateFirebaseAPI(schema, outputDir, type) {
if (type === 'rest') {
await generateRESTAPI(schema, outputDir);
} else if (type === 'graphql') {
await generateGraphQLAPI(schema, outputDir);
}
}
async function generateRESTAPI(schema, outputDir) {
// Generate model
const modelContent = generateModelContent(schema);
await fs.writeFile(
path.join(outputDir, `${schema.name}.model.js`),
modelContent
);
// Generate controller
const controllerContent = generateControllerContent(schema);
await fs.writeFile(
path.join(outputDir, `${schema.name}.controller.js`),
controllerContent
);
// Generate routes
const routesContent = generateRoutesContent(schema);
await fs.writeFile(
path.join(outputDir, `${schema.name}.routes.js`),
routesContent
);
// Generate Firebase security rules
const rulesContent = generateSecurityRules(schema);
await fs.writeFile(
path.join(outputDir, 'firestore.rules'),
rulesContent
);
}
function generateModelContent(schema) {
return `
const admin = require('firebase-admin');
const db = admin.firestore();
const collection = db.collection('${schema.name.toLowerCase()}s');
class ${schema.name} {
constructor(data) {
${Object.keys(schema.fields).map(field =>
`this.${field} = data.${field};`
).join('\n ')}
this.createdAt = data.createdAt || new Date();
this.updatedAt = data.updatedAt || new Date();
}
static async create(data) {
const doc = await collection.add({
...data,
createdAt: new Date(),
updatedAt: new Date()
});
return { id: doc.id, ...data };
}
static async findAll(options = {}) {
const { limit = 10, page = 1, orderBy = 'createdAt', orderDir = 'desc' } = options;
const offset = (page - 1) * limit;
let query = collection.orderBy(orderBy, orderDir);
const snapshot = await query.get();
const total = snapshot.size;
query = query.limit(limit).offset(offset);
const docs = await query.get();
return {
items: docs.docs.map(doc => ({ id: doc.id, ...doc.data() })),
total,
totalPages: Math.ceil(total / limit),
currentPage: page
};
}
static async findById(id) {
const doc = await collection.doc(id).get();
if (!doc.exists) return null;
return { id: doc.id, ...doc.data() };
}
static async update(id, data) {
const ref = collection.doc(id);
const doc = await ref.get();
if (!doc.exists) return null;
await ref.update({
...data,
updatedAt: new Date()
});
const updated = await ref.get();
return { id: updated.id, ...updated.data() };
}
static async delete(id) {
const ref = collection.doc(id);
const doc = await ref.get();
if (!doc.exists) return false;
await ref.delete();
return true;
}
}
module.exports = ${schema.name};
`;
}
function generateControllerContent(schema) {
return `
const ${schema.name} = require('./${schema.name}.model');
// Create
exports.create = async (req, res) => {
try {
const new${schema.name} = await ${schema.name}.create(req.body);
res.status(201).json(new${schema.name});
} catch (error) {
res.status(400).json({ message: error.message });
}
};
// Read all
exports.findAll = async (req, res) => {
try {
const { page = 1, limit = 10, orderBy, orderDir } = req.query;
const items = await ${schema.name}.findAll({
page: parseInt(page),
limit: parseInt(limit),
orderBy,
orderDir
});
res.json(items);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
// Read one
exports.findOne = async (req, res) => {
try {
const item = await ${schema.name}.findById(req.params.id);
if (!item) {
return res.status(404).json({ message: 'Item not found' });
}
res.json(item);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
// Update
exports.update = async (req, res) => {
try {
const updated${schema.name} = await ${schema.name}.update(req.params.id, req.body);
if (!updated${schema.name}) {
return res.status(404).json({ message: 'Item not found' });
}
res.json(updated${schema.name});
} catch (error) {
res.status(400).json({ message: error.message });
}
};
// Delete
exports.delete = async (req, res) => {
try {
const deleted = await ${schema.name}.delete(req.params.id);
if (!deleted) {
return res.status(404).json({ message: 'Item not found' });
}
res.json({ message: 'Item deleted successfully' });
} catch (error) {
res.status(500).json({ message: error.message });
}
};
`;
}
function generateRoutesContent(schema) {
return `
const express = require('express');
const router = express.Router();
const ${schema.name}Controller = require('./${schema.name}.controller');
// Create
router.post('/', ${schema.name}Controller.create);
// Read all
router.get('/', ${schema.name}Controller.findAll);
// Read one
router.get('/:id', ${schema.name}Controller.findOne);
// Update
router.put('/:id', ${schema.name}Controller.update);
// Delete
router.delete('/:id', ${schema.name}Controller.delete);
module.exports = router;
`;
}
function generateSecurityRules(schema) {
return `
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /${schema.name.toLowerCase()}s/{document=**} {
allow read: if true;
allow create: if request.auth != null;
allow update: if request.auth != null &&
request.auth.uid == resource.data.userId;
allow delete: if request.auth != null &&
request.auth.uid == resource.data.userId;
}
}
}
`;
}
module.exports = {
generateFirebaseAPI
};