We need to create a POST route that will insert new tree data into our database. Think of this like adding a new card to a deck - we need to make sure all the required information is there and properly formatted before we add it.
Expected Input Example:
{
"name": "My Big Tree",
"location": "My Backyard",
"height": 123.4,
"size": 57.9
}
Expected Output Example:
{
"status": "success",
"message": "Successfully created new tree",
"data": {
"id": 7,
"tree": "My Big Tree",
"location": "My Backyard",
"heightFt": 123.4,
"groundCircumferenceFt": 57.9,
"updatedAt": "2025-02-17T...",
"createdAt": "2025-02-17T..."
}
}
// POST route to create a new tree
router.post('/', async (req, res, next) => {
// Extract data from request body
const { name, location, height, size } = req.body;
try {
// Create new tree record
// Note the mapping between request fields and database columns
const tree = await Tree.create({
tree: name, // 'name' in request becomes 'tree' in DB
location: location,
heightFt: height, // 'height' becomes 'heightFt'
groundCircumferenceFt: size // 'size' becomes 'groundCircumferenceFt'
});
// Return success response with new tree data
res.json({
status: "success",
message: "Successfully created new tree",
data: tree
});
} catch (err) {
// Handle potential errors
next({
status: "error",
message: "Could not create new tree",
details: err.errors ? err.errors.map(item => item.message) : err.message
});
}
});
This pattern is used in many real-world scenarios:
Think of field mapping like translation between two languages. In our case:
| Request Field (Client Language) | Database Field (Server Language) |
|---|---|
| name | tree |
| height | heightFt |
| size | groundCircumferenceFt |
You can test this implementation in several ways:
npm test test/phase-02-spec.jsWatch out for these common issues:
A more sophisticated version might include:
router.post('/', async (req, res, next) => {
// Input validation middleware
const validateTree = (data) => {
const errors = [];
if (!data.name) errors.push("Name is required");
if (!data.height || data.height <= 0) errors.push("Valid height is required");
if (!data.size || data.size <= 0) errors.push("Valid size is required");
return errors;
};
try {
// Validate input
const validationErrors = validateTree(req.body);
if (validationErrors.length > 0) {
throw new Error(validationErrors.join(', '));
}
// Normalize data
const treeData = {
tree: req.body.name.trim(),
location: (req.body.location || 'Unknown').trim(),
heightFt: parseFloat(req.body.height),
groundCircumferenceFt: parseFloat(req.body.size)
};
// Create with transaction
const tree = await sequelize.transaction(async (t) => {
return await Tree.create(treeData, { transaction: t });
});
// Return success response
res.status(201).json({
status: "success",
message: "Successfully created new tree",
data: tree
});
} catch (err) {
next(err);
}
});
To better understand this concept, try these exercises: