In this tutorial, we’ll create a simple CRUD application for managing Student
entities using TypeORM with MySQL. We’ll use the crypto
library for encrypting data at rest (stored data) to ensure data security. We will not cover data in transit encryption here, but typically HTTPS is used for that purpose.
1. Set Up the Project
- Initialize a Node.js Project
mkdir student-crud
cd student-crud
npm init -y
Install Dependencies
Install the necessary packages:
npm install express typeorm mysql2 crypto
2. Configure TypeORM with MySQL
- Create a
ormconfig.js
FileConfigure TypeORM to connect to your MySQL database:
// ormconfig.js
module.exports = {
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root', // Replace with your MySQL username
password: 'password', // Replace with your MySQL password
database: 'testdb', // Replace with your database name
entities: [__dirname + '/src/entity/*.js'],
synchronize: true, // Set to false in production
};
Create the Student
Entity
Use EntitySchema
for defining the Student
entity:
// src/entity/Student.js
const { EntitySchema } = require('typeorm');
module.exports = new EntitySchema({
name: 'Student',
tableName: 'students',
columns: {
id: {
type: 'int',
primary: true,
generated: true,
},
name: {
type: 'varchar',
length: 255,
nullable: false,
},
email: {
type: 'varchar',
length: 255,
unique: true,
nullable: false,
},
age: {
type: 'int',
nullable: false,
},
encryptedData: {
type: 'varchar',
length: 255,
nullable: true,
},
},
});
3. Create Encryption Helper Functions
- Create
cryptoHelper.js
for EncryptionCreate functions for encrypting and decrypting data:
// src/cryptoHelper.js
const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32); // 32 bytes = 256 bits
const iv = crypto.randomBytes(16); // 16 bytes IV
const encrypt = (text) => {
let cipher = crypto.createCipheriv(algorithm, Buffer.from(key), iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex') };
};
const decrypt = (text, iv) => {
let ivBuffer = Buffer.from(iv, 'hex');
let encryptedText = Buffer.from(text, 'hex');
let decipher = crypto.createDecipheriv(algorithm, Buffer.from(key), ivBuffer);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
};
module.exports = { encrypt, decrypt };
4. Create a Simple CRUD Application
- Create
app.js
Set up Express, connect to the database, and create CRUD endpoints. We will integrate the encryption helper functions into our CRUD operations:
// app.js
const express = require('express');
const { createConnection, getRepository } = require('typeorm');
const Student = require('./src/entity/Student');
const { encrypt, decrypt } = require('./src/cryptoHelper');
const app = express();
app.use(express.json());
// Connect to the database
createConnection().then(() => {
console.log('Connected to the database');
// Create a new student
app.post('/students', async (req, res) => {
const studentRepository = getRepository(Student);
try {
const { name, email, age, sensitiveData } = req.body;
const encrypted = encrypt(sensitiveData); // Encrypt sensitive data
const student = studentRepository.create({
name,
email,
age,
encryptedData: JSON.stringify(encrypted),
});
await studentRepository.save(student);
res.status(201).json(student);
} catch (error) {
console.error('Error creating student:', error);
res.status(500).json({ message: 'Failed to create student' });
}
});
// Get all students
app.get('/students', async (req, res) => {
const studentRepository = getRepository(Student);
try {
const students = await studentRepository.find();
// Decrypt data if needed
students.forEach(student => {
if (student.encryptedData) {
const { encryptedData, iv } = JSON.parse(student.encryptedData);
student.decryptedData = decrypt(encryptedData, iv); // Decrypt data
}
});
res.json(students);
} catch (error) {
console.error('Error getting students:', error);
res.status(500).json({ message: 'Failed to get students' });
}
});
// Get a student by ID
app.get('/students/:id', async (req, res) => {
const studentRepository = getRepository(Student);
try {
const student = await studentRepository.findOne(req.params.id);
if (!student) {
return res.status(404).json({ message: 'Student not found' });
}
// Decrypt data if needed
if (student.encryptedData) {
const { encryptedData, iv } = JSON.parse(student.encryptedData);
student.decryptedData = decrypt(encryptedData, iv); // Decrypt data
}
res.json(student);
} catch (error) {
console.error('Error getting student:', error);
res.status(500).json({ message: 'Failed to get student' });
}
});
// Update a student
app.put('/students/:id', async (req, res) => {
const studentRepository = getRepository(Student);
try {
const student = await studentRepository.findOne(req.params.id);
if (!student) {
return res.status(404).json({ message: 'Student not found' });
}
const { name, email, age, sensitiveData } = req.body;
if (sensitiveData) {
const encrypted = encrypt(sensitiveData); // Encrypt sensitive data
student.encryptedData = JSON.stringify(encrypted);
}
student.name = name || student.name;
student.email = email || student.email;
student.age = age || student.age;
await studentRepository.save(student);
res.json(student);
} catch (error) {
console.error('Error updating student:', error);
res.status(500).json({ message: 'Failed to update student' });
}
});
// Delete a student
app.delete('/students/:id', async (req, res) => {
const studentRepository = getRepository(Student);
try {
const student = await studentRepository.findOne(req.params.id);
if (!student) {
return res.status(404).json({ message: 'Student not found' });
}
await studentRepository.remove(student);
res.status(204).end();
} catch (error) {
console.error('Error deleting student:', error);
res.status(500).json({ message: 'Failed to delete student' });
}
});
// Start the server
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
}).catch(error => {
console.error('Database connection failed', error);
});
Brief Explanation
- Encryption Helper:
cryptoHelper.js
provides functions to encrypt and decrypt data.encrypt(text)
: Encrypts the input text and returns the encrypted data and IV.decrypt(encryptedText, iv)
: Decrypts the input data using the provided IV.
- CRUD Operations:
- Create: Encrypt sensitive data before saving it to the database.
- Read: Decrypt sensitive data when retrieving it from the database.
- Update: Encrypt data before updating the record in the database.
- Delete: Standard CRUD operation without encryption.
- TypeORM: Manages database interactions using the
Student
entity schema.
By following these steps, you’ll have a simple CRUD application with data encryption for sensitive information stored in a MySQL database.