Сьогодні я розпочав подорож з кодування для створення динамічного API управління формами. Мета полягала в тому, щоб створити систему, де форми можна призначати до певних категорій (наприклад, Куб, Квадрат і Циліндр) і керувати ними через операції CRUD. Цей процес навчив мене цінним урокам щодо розробки API, ініціалізації бази даних і організації коду для масштабованості.
У цій статті я поділюсь тим, що я досяг, з якими викликами стикнувся і чітким планом для тих, хто хоче створити подібний проект.
Що я дізнався сьогодні
1. Структурування проекту на Node.js для розробки API
Добре структурований проект є основою ефективної розробки. Ось структура директорій, яку я використав для цього проекту:
project/
│
├── models/
│ ├── shapeModel.js # Схема для форми
│ ├── categoryShapeModel.js # Схема для категорії
│
├── controllers/
│ ├── shapeController.js # Логіка для управління формами
│
├── routes/
│ ├── shapeRoutes.js # Маршрути для кінцевих точок, пов'язаних з формами
│
├── config/
│ ├── db.js # Логіка підключення до MongoDB
│
├── seedCategories.js # Скрипт для одноразової вставки категорій
├── app.js # Основна точка входу
├── .env # Змінні середовища
└── package.json # Залежності
2. Створення схем MongoDB
Я навчився, як визначати схеми для форм і категорій. Ці схеми забезпечують узгодженість у базі даних, дозволяючи створювати потужні взаємозв'язки, наприклад, прив'язуючи форми до категорій.
Схема категорії
const mongoose = require("mongoose");
const categorySchema = mongoose.Schema(
{
name: {
type: String,
required: true,
unique: true,
enum: ["Cube", "Square", "Cylinder"],
},
},
{ timestamps: true }
);
module.exports = mongoose.model("Category", categorySchema);
Схема форми
const mongoose = require("mongoose");
const shapeSchema = mongoose.Schema(
{
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
required: true,
},
color: { type: String, required: true },
size: { type: Number, required: true },
position: {
x: { type: Number, required: true },
y: { type: Number, required: true },
z: { type: Number, required: true },
},
rotation: {
x: { type: Number, required: true },
y: { type: Number, required: true },
z: { type: Number, required: true },
},
},
{ timestamps: true }
);
module.exports = mongoose.model("Shape", shapeSchema);
3. Ініціалізація бази даних
Я розв'язав задачу ініціалізації попередньо визначених категорій (“Cube,” “Square,” “Cylinder”) у базі даних. Замість того, щоб додавати ці записи вручну, я створив скрипт ініціалізації, який запускається один раз і автоматично вставляє дані.
Скрипт ініціалізації
const mongoose = require("mongoose");
const Category = require("./models/categoryShapeModel");
const dotenv = require("dotenv");
dotenv.config();
const connectDB = async () => {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log("MongoDB connected");
};
const seedCategories = async () => {
const categories = ["Cube", "Square", "Cylinder"];
for (const name of categories) {
const exists = await Category.findOne({ name });
if (!exists) {
await Category.create({ name });
console.log(`Inserted category: ${name}`);
} else {
console.log(`Category ${name} already exists`);
}
}
process.exit();
};
(async () => {
await connectDB();
await seedCategories();
})();
4. Створення RESTful кінцевих точок
Я створив CRUD (Create, Read, Update, Delete) кінцеві точки для управління формами.
Кожна кінцева точка включає обробку помилок, щоб забезпечити надійність функціональності.
Кінцеві точки
- GET
/api/shapes/:categoryId
- Отримати всі форми для конкретної категорії. - POST
/api/shapes/:categoryId
- Додати нову форму до категорії. - PUT
/api/shapes/:id
- Оновити деталі форми. - DELETE
/api/shapes/:id
- Видалити форму.
Приклад: Контролер для додавання форми
const addShape = async (req, res) => {
const { color, size, position, rotation } = req.body;
try {
const category = await Category.findById(req.params.categoryId);
if (!category) {
return res.status(404).json({ message: "Категорію не знайдено" });
}
const shape = new Shape({
category: category._id,
color,
size,
position,
rotation,
});
const savedShape = await shape.save();
res.status(201).json(savedShape);
} catch (error) {
res.status(500).json({ message: "Помилка при додаванні форми", error });
}
};
5. Підключення до MongoDB
Щоб підключити моє API до MongoDB, я створив багаторазову утиліту підключення:
const mongoose = require("mongoose");
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log("MongoDB успішно підключено");
} catch (error) {
console.error("Помилка підключення до MongoDB", error);
process.exit(1);
}
};
module.exports = connectDB;
План на наступні кроки
Ось що я планую робити далі:
- Реалізація аутентифікації
- Додати ролі користувачів (Admin, User) для контролю доступу.
- Захистити кінцеві точки API за допомогою JWT.
2. Створення фронтенду
- Використати React для створення інтерфейсу для керування формами та категоріями.
- Дозволити користувачам динамічно візуалізувати форми.
3. Логування помилок і моніторинг
- Інтегрувати інструменти, такі як Winston або Morgan, для детального відстеження помилок.
4. Документація API
- Використати Swagger або Postman для документування всіх кінцевих точок для зручного тестування.
Перекладено з: Building a Dynamic Shape Management API with Node.js and MongoDB: My Journey and Lessons Learned