Skip to content

Commit

Permalink
Mongoose Middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
marieaurore123 committed Feb 4, 2021
1 parent 78d26c3 commit 9398a7b
Show file tree
Hide file tree
Showing 8 changed files with 957 additions and 83 deletions.
129 changes: 55 additions & 74 deletions controllers/bootcamps.js
Original file line number Diff line number Diff line change
@@ -1,106 +1,87 @@
const { findByIdAndDelete } = require('../models/Bootcamp');
const Bootcamp = require('../models/Bootcamp');
const ErrorResponse = require('../utils/errorResponse');
const asyncHandler = require('../middleware/async');

/**
* NOTES
* - Need body parser middleware (in server.js) in order to access "req.body" within these functions
* - Always wrap in trycatch
* - Always wrap in trycatch OR use asyncHandler
* - If client sends data that is not in the model, it gets ignored
*/

// @desc Get all bootcamps
// @route GET /api/v1/bootcamps
// @access Public
exports.getBootcamps = async (req, res, next) => {
try {
const bootcamps = await Bootcamp.find();
res.status(200).json({
success: true,
count: bootcamps.length,
data: bootcamps
})
} catch (err) {
res.status(400).json({
success: false
});
}
};
exports.getBootcamps = asyncHandler(async (req, res, next) => {
const bootcamps = await Bootcamp.find();
res.status(200).json({
success: true,
count: bootcamps.length,
data: bootcamps
})

// Catch block --> next(err);
});

// @desc Get single bootcamps
// @route GET /api/v1/bootcamps/:id
// @access Public
exports.getBootcamp = async (req, res, next) => {
try {
const bootcamp = await Bootcamp.findById(req.params.id);
exports.getBootcamp = asyncHandler(async (req, res, next) => {
const bootcamp = await Bootcamp.findById(req.params.id);

// handle err if id does not match any bootcamps
if (!bootcamp) return res.status(400).json({success: false});
// handle err if id does not match any bootcamps in database
if (!bootcamp) return next(new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404));

res.status(200).json({
success: true,
data: bootcamp
})
} catch (err) {
// handle err if id is not correct format (ie. # of digits)

// res.status(400).json({
// success: false
// });
next(err);
}
};
res.status(200).json({
success: true,
data: bootcamp
})

// Catch block - handle err if id is not correct format (ie. # of digits) --> asyncHandler
// next(err);

});

// @desc Create new bootcamp
// @route POST /api/v1/bootcamps
// @access Private
exports.createBootcamp = async (req, res, next) => {
try {
const bootcamp = await Bootcamp.create(req.body);
exports.createBootcamp = asyncHandler(async (req, res, next) => {
const bootcamp = await Bootcamp.create(req.body);

res.status(201).json({
success: true,
data: bootcamp
});
} catch (err) {
res.status(400).json({success: false});
}
};
res.status(201).json({
success: true,
data: bootcamp
});

// Catch block --> handles duplicate keys AND handles form validation
// next(err);
});

// @desc Update single bootcamp
// @route PUT /api/v1/bootcamps/:id
// @access Private
exports.updateBootcamp = async (req, res, next) => {
try {
const bootcamp = await Bootcamp.findByIdAndUpdate(
req.params.id,
req.body,
{
new: true, // response become supdates data
runValidators: true
}
);

if (!bootcamp) return res.status(400).json({success: false});

res.status(200).json({success: true, data: bootcamp});
} catch (err) {
res.status(400).json({success: false});
}

};
exports.updateBootcamp = asyncHandler(async (req, res, next) => {
const bootcamp = await Bootcamp.findByIdAndUpdate(
req.params.id,
req.body,
{
new: true, // response become supdates data
runValidators: true
}
);

if (!bootcamp) return next(new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404));

res.status(200).json({success: true, data: bootcamp});
});

// @desc Delete Single Bootcamp
// @route DELETE /api/v1/bootcamps/:id
// @access Provate
exports.deleteBootcamp = async (req, res, next) => {
try {
const bootcamp = await Bootcamp.findByIdAndDelete(req.params.id);

if (!bootcamp) return res.status(400).json({success: false});
exports.deleteBootcamp = asyncHandler(async (req, res, next) => {
const bootcamp = await Bootcamp.findByIdAndDelete(req.params.id);

res.status(200).json({success: true, data: {}});
if (!bootcamp) return next(new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404));

} catch (err) {
res.status(400).json({success: false});
}
};
res.status(200).json({success: true, data: {}});
});
4 changes: 4 additions & 0 deletions middleware/async.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const asyncHandler = fn => (req, res, next) =>
Promise.resolve(fn(req, res, next)).catch(next);

module.exports = asyncHandler;
30 changes: 27 additions & 3 deletions middleware/error.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
const ErrorResponse = require("../utils/errorResponse");

const errorHandler = (err, req, res, next) => {
let error = {...err}

error.message = err.message;

// Log to console for dev
console.log(err.stack.red);
console.log(err);

// Mongoose bad object id format (ObjectId is object's _id passed in url)
if (err.name === 'CastError') {
const message = `Bootcamp not found with id of ${err.value}`; // console.log(err) to see all err fields
error = new ErrorResponse(message, 404);
}

// Mongoose duplicate key
if (err.code === 11000) {
const message = 'Duplicate field value entered';
error = new ErrorResponse(message, 400);
}

// Mongoose validation error (client not sending required fields)
if (err.name === 'ValidationError') {
const message = Object.values(err.errors).map(val => val.message); // console.log(err) to see err.errors array
error = new ErrorResponse(message, 400);
}

res.status(500).json({
res.status(error.statusCode).json({
success: false,
error: err.message
error: error.message || 'Server Error'
});
}

Expand Down
36 changes: 36 additions & 0 deletions models/Bootcamp.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const mongoose = require('mongoose');
const slugify = require('slugify');
const geocoder = require('../utils/geocoder');

const BootcampSchema = new mongoose.Schema({
name: {
Expand Down Expand Up @@ -99,4 +101,38 @@ const BootcampSchema = new mongoose.Schema({
}
});

// Create bootcamp slug from the name
BootcampSchema.pre('save', function(next) { // this will run before saving

console.log('Slugify ran', this.name); // notice that this runs when the model is created (through API)

// all model fields can be access as so:
this.slug = slugify(this.name, { lower:true }); // check slugify doc

// API response will contain the newly created slug field

next();
})

// Geocode and create location field
BootcampSchema.pre('save', async function(next) {
const loc = await geocoder.geocode(this.address);

this.location = {
type: 'Point',
coordinates: [loc[0].longitude, loc[0].latitude],
formattedAddress: loc[0].formattedAddress,
street: loc[0].streetName,
city: loc[0].city,
state: loc[0].stateCode,
zipcode: loc[0].zipCode,
country: loc[0].countryCode
};

// Do not save address inputed by client in DB (use formattedAddress given by geocoder instead)
this.address = undefined;

next();
});

module.exports = mongoose.model('Bootcamp', BootcampSchema);
Loading

0 comments on commit 9398a7b

Please sign in to comment.