Build Your Own Micro Framework and ORM with Node.js
AtomixWeb Pvt. Ltd
Specialized in custom Solutions Web Development, Mobile Applications, Cyber Security, Cloud solution
Welcome to our latest newsletter! In this edition, we will walk you through creating your own micro-framework and ORM using Node.js. Whether you're looking to deepen your understanding of web development or create something custom-tailored to your needs, this tutorial has you covered.
Introduction
Creating your micro-framework can give you greater control over your projects, improve your understanding of underlying technologies, and provide a lightweight alternative to full-fledged frameworks like Express.js. We'll also include a simple ORM to interact with SQL databases.
Step 1: Setting Up Your Project
First, set up a new Node.js project and install the required packages:
Initialize the Project
mkdir my-micro-framework
cd my-micro-framework
npm init -y
Install Dependencies
npm install sqlite3
Step 2: Creating the Micro Framework
Let's create a basic structure for our micro framework, named Atomix. It will support REST API development with middleware, routing, and basic ORM functionality.
2.1 Creating the Core Framework
Create a file named atomix.js and start with the basic setup:
const http = require('http');
const fs = require('fs');
const path = require('path');
const url = require('url');
const sqlite3 = require('sqlite3').verbose();
class Atomix {
constructor() {
this.routes = [];
this.middlewares = [];
this.templateRoot = path.join(__dirname, 'templates'); // Set template root
}
use(middleware) {
this.middlewares.push(middleware);
}
route(method, path, handler) {
this.routes.push({ method, path, handler });
}
async handler(req, res) {
try {
const parsedUrl = url.parse(req.url, true);
req.pathname = parsedUrl.pathname;
req.query = parsedUrl.query;
req.body = await this.parseBody(req);
for (const middleware of this.middlewares) {
await middleware(req, res);
if (res.finished) return;
}
const matchingRoute = this.routes.find(route => route.path === req.pathname && route.method === req.method);
if (matchingRoute) {
matchingRoute.handler(req, res);
} else {
res.statusCode = 404;
res.end('404 Not Found');
}
} catch (err) {
res.statusCode = 500;
res.end('500 Internal Server Error');
}
}
parseBody(req) {
return new Promise((resolve, reject) => {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
resolve(body ? JSON.parse(body) : {});
});
});
}
listen(port) {
this.server = http.createServer((req, res) => this.handler(req, res));
this.server.listen(port, () => {
console.log(`Server running at https://localhost:${port}/`);
});
}
render(res, templateName) {
const filePath = path.join(this.templateRoot, templateName);
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
res.statusCode = 500;
res.end('500 Internal Server Error');
return;
}
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(data);
});
}
static(dir) {
return (req, res, next) => {
const filePath = path.join(dir, req.pathname);
fs.readFile(filePath, (err, data) => {
if (err) {
next();
} else {
res.statusCode = 200;
res.end(data);
}
});
};
}
}
2.2 Adding a Simple ORM
Create a basic ORM to handle SQL-based databases. Add the following class to the atomix.js file:
class ORM {
constructor(dbFile) {
this.db = new sqlite3.Database(dbFile);
}
createTable(tableName, columns) {
const cols = columns.map(col => `${col.name} ${col.type}`).join(', ');
const query = `CREATE TABLE IF NOT EXISTS ${tableName} (${cols})`;
return this.run(query);
}
insert(tableName, data) {
const columns = Object.keys(data).join(', ');
const placeholders = Object.keys(data).map(() => '?').join(', ');
const query = `INSERT INTO ${tableName} (${columns}) VALUES (${placeholders})`;
return this.run(query, Object.values(data));
}
get(tableName, conditions = {}) {
const whereClause = Object.keys(conditions).map(key => `${key} = ?`).join(' AND ');
const query = `SELECT * FROM ${tableName}${whereClause ? ' WHERE ' + whereClause : ''}`;
return this.all(query, Object.values(conditions));
}
run(query, params = []) {
return new Promise((resolve, reject) => {
this.db.run(query, params, function (err) {
if (err) {
reject(err);
} else {
resolve(this);
}
});
});
}
all(query, params = []) {
return new Promise((resolve, reject) => {
this.db.all(query, params, (err, rows) => {
if (err) {
reject(err);
} else {
resolve(rows);
}
});
});
}
}
领英推荐
2.3 Using the Framework
Create a file named server.js to use the Atomix framework:
const Atomix = require('./atomix');
const orm = new Atomix.ORM('database.db');
const app = new Atomix();
// Middleware to log requests
app.use(async (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
// Serve static files from the 'public' directory
app.use(app.static('public'));
// Define a route for GET requests
app.route('GET', '/', (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ message: 'Welcome to the API!' }));
});
// Define a route for POST requests
app.route('POST', '/data', async (req, res) => {
const data = req.body;
await orm.insert('testTable', data);
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ message: 'Data inserted', data }));
});
// Create a test table
orm.createTable('testTable', [
{ name: 'id', type: 'INTEGER PRIMARY KEY AUTOINCREMENT' },
{ name: 'name', type: 'TEXT' },
{ name: 'age', type: 'INTEGER' }
]).then(() => {
// Start the server on port 3000
app.listen(3000);
});
Step 3: Running Your Project
Create Necessary Directories
Create directories for static files and templates
mkdir public templates
Create Sample HTML Files
Run the Server
node server.js
You should see your server running on https://localhost:3000, with endpoints for handling GET and POST requests, logging middleware, and a simple ORM for database interactions.
Conclusion
Congratulations! You've built a micro framework and a basic ORM in Node.js. This tutorial demonstrates the power of understanding underlying technologies and creating custom solutions tailored to your needs. We hope this tutorial has been informative and inspiring.
Stay tuned for more tutorials and insights in our next newsletter!
If you found this tutorial helpful, please share it with your network and follow us for more tips and tricks in web development and software engineering.
Happy coding!
This is a comprehensive newsletter tutorial designed to guide readers through building their own micro-framework and ORM with Node.js. Feel free to customize and expand upon this framework to suit your specific needs.