Display error message while making Get api - javascript

I am making a get api using node js and express js framework and this is the code which I am writing
controllers/biz_plans.js
const getbizPlans = (req, res, next) => {
return db.coaching_classes.findAll({})
.then(classes => {
if (classes && classes.length > 0) {
return res.status(200).send(classes)
}
else {
console.log('not found');
return res.status(404).send({
error_message: 'no classes available',
});
}
})
.catch(next);
};
and my routes.js is
var express = require('express');
var router = express.Router();
var db = require('../models');
var organizationsController = require('../controllers/bizPlans')
/* GET coaching_plans listing. */
router.get('/',organizationsController.getbizPlans);
module.exports = router;
If Data is there in the database this api is running but when data is not there in the database it should display the error message which I am trying to display but it is not displaying anything in the browser.
I am not able to understand what I am missing I have checked various links regarding this and everywhere same approach I found but it is not working for me .

Try using the catch function to return the error?
.catch(err => {
console.log(err);
return res.status(404).send({
error_message: 'no classes available'
});
});

Related

Having some problems trying to call a function from another script

I'm building a mockup website to try and learn NodeJS. I want a login system and I'm trying to connect my register page with my database script. The sql function that sends queries to the database is working as intended, however, when trying to call the query function from the script that manages the register webpage all I get is an error 500.
It would be cool if someone could point me in the right direction, surely it's some quirk from NodeJS I don't know about yet.
Here is my register page script that should call the query function from POST routing:
var express = require('express');
var router = express.Router();
var db = require('../public/javascripts/dbController');
router
.get('/', function(req, res, next) {
res.render('register.html', {title: 'Register'})
})
.post('/', function(req, res, next) {
register(req.body);
res.render('register.html', {title: 'Register'})
})
function register(request)
{
let username = request.login;
let password = request.password;
let sql = "INSERT INTO users (user_username, user_password, user_status) VALUES ('"+username+"','"+password+"', 1);";
console.log("query");
//Why is this not working?
db.query(sql);
}
module.exports = router;
And here is (part of) my dbController script:
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('./public/database/db.db', sqlite3.OPEN_READWRITE, (err) => {
if (err && err.code == "SQLITE_CANTOPEN") {
createDatabase();
return;
} else if (err) {
console.log("Getting error " + err);
exit(1);
}
});
//This function is not running when I ask for it in register.js
function query(sql){
console.log("running query: " + sql)
db.all(sql, [], (err, rows) => {
if (err) {
throw err;
}
rows.forEach((row) => {
console.log(row.name);
});
});
}
module.exports = query;
I figure that I probably have to route my scripts through the main app script or maybe I'm exporting wrong? Anyway, any nudge in the right direction would be great because I've been stuck on it a few days. Thanks!
For what I can see, you're indeed importing the "query" function into your "register" page. But you're setting a name of "db" to it.
var db = require('../public/javascripts/dbController');
but you're not exporting "db" you're exporting "query":
module.exports = query;
But that's not really the issue, you could just call it "myRandomNameImport" and it would still work. The problem is that you're accessing a property of "db" that does not exist.
db.query(sql); /* <- db.query does not exist.
* Try db(sql) instead. */
"db" does not have any properties called "query", the function you're trying to use is "db".
function register(request) {
let username = request.login;
let password = request.password;
let sql = "INSERT INTO users (user_username, user_password, user_status) VALUES ('"+username+"','"+password+"', 1);";
console.log("query");
db(sql); /*<- Just call db()*/
}

CRUD operations using mongoose and express

I am creating an express app using mongoose with the intention of connecting this to React for the frontend.
I have listed some CRUD operations for a customer controller below but there are a few things I do not like about this approach.
When using Customer.findById with a valid ObjectID that is not found, it returns null with a 200 response code. I want this to return 404 if no customer was found. I realise I could change the catch response to a 404, but I want to have some generic error handling incase the server goes down during the request or an invalid ObjectId was provided, which brings me to my next item.
If I provide an invalid ObjectId I want to provide some meaningful message, is 500 the right response code?
Error handling: Am I returning errors the correct way? currently errors return a string with the error message. Should I return JSON instead? e.g. res.status(500).json({error: error.message). I am planning on connecting this to react (which I am still learning) and I assume the UI will need to display these messages to the user?
findById is repeated in getCustomerById, updateCustomer, and deleteCustomer. I feel this is bad practice and there must be a more streamlined approach?
I want to have one function that validates if the ObjectId is valid. I am aware that I can do this is the routes using router.params but I'm not sure if checking for a valid id should be in the routes file as it seems like something the controller should be handling? See routes example below from another project I did.
What are the best practices and suggested ways to improve my code, based on the above?
I have read the documentation from mongoose, mozilla, and stackoverflow Q&A but they don't seem to address these issues (at least I could not find it).
I am really after some guidance or validation that what I am doing is correct or wrong.
customer.controller.js
const Customer = require("../models/customer.model");
exports.getCustomers = async (req, res) => {
try {
const customers = await Customer.find();
res.status(200).json(customers);
} catch (error) {
res.status(500).send(error.message);
}
};
exports.getCustomerById = async (req, res) => {
try {
const customer = await Customer.findById(req.params.id);
res.status(200).json(customer);
} catch (error) {
res.status(500).send(error.message);
}
};
exports.addCustomer = async (req, res) => {
try {
const customer = new Customer(req.body);
await customer.save().then(res.status(201).json(customer));
} catch (error) {
res.status(500).send(error.message);
}
};
exports.updateCustomer = async (req, res) => {
try {
const customer = await Customer.findById(req.params.id);
Object.assign(customer, req.body);
customer.save();
res.status(200).json(customer);
} catch (error) {
res.status(500).send(error.message);
}
};
exports.deleteCustomer = async (req, res) => {
try {
const customer = await Customer.findById(req.params.id);
await customer.remove();
res.status(200).json(customer);
} catch (error) {
res.status(500).send(error.message);
}
};
Router.params example
This is a routes file (not related to my current app) and is provided as an example of how I have used router.params in the past.
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const Artist = require("../models/Artist");
const loginRequired = require("../middleware/loginRequired");
const {
getArtists,
addArtist,
getArtistById,
updateArtist,
deleteArtist,
} = require("../controllers/artistController");
router
.route("/")
.get(loginRequired, getArtists) // Get all artists
.post(loginRequired, addArtist); // Create a new artist
router
.route("/:id")
.get(loginRequired, getArtistById) // Get an artist by their id
.put(loginRequired, updateArtist) // Update an artist by their id
.delete(loginRequired, deleteArtist); // Delete an artist by their id
router.param("id", async (req, res, next, id) => {
// Check if the id is a valid Object Id
if (mongoose.isValidObjectId(id)) {
// Check to see if artist with valid id exists
const artist = await Artist.findOne({ _id: id });
if (!artist) res.status(400).json({ errors: "Artist not found" });
res.locals.artist = artist;
res.locals.artistId = id;
next();
} else {
res.status(400).json({ errors: "not a valid object Id" });
}
});
module.exports = router;
i personly like to make error handeling more global so i would write something like
constPrettyError = require('pretty-error')
const pe = new PrettyError()
const errorHandler = (err, req, res, next) => {
if (process.env.NODE_ENV !== 'test') {
console.log(pe.render(err))
}
return res
.status(err.status || 500)
.json({ error: { message: err.message || 'oops something went wrong' } })
}
module.exports = errorHandler
as a handler
the in your index / server file
app.use(errorHandler)
then in your handlers just
} catch (err) {
next(err);
}
as an example
if (!artist) next({ message: "Artist not found" ,status:404 });
also, note that you can customize this error handler to switch case (or object) a custom error per status as well if you want
const errorHandler = (err, req, res, next) => {
if (process.env.NODE_ENV !== 'test') {
console.log(pe.render(err))
}
const messagePerStatus = {
404: 'not found',
401: 'no authorization'
}
const message = messagePerStatus[err.status]
return res
.status(err.status || 500)
.json({
error: { message: message || err.message || 'oops something went wrong' }
})
}
then just
if (!artist) next({status:404 });
I also agree with answer by Asaf Strilitz but still need to show what i do in my projects
Create a custom error class
AppError.js
class AppError extends Error {
constructor(statusCode, message) {
super();
// super(message);
this.statusCode = statusCode || 500 ;
this.message = message || "Error Something went wrong";
}
}
module.exports = AppError;
Create an error handling middleware
errors.js
const AppError = require("../helpers/appError");
const errors = (err, req, res, next) => {
// console.log(err);
let error = { ...err };
error.statusCode = error.statusCode;
error.message = error.message;
res.status(error.statusCode).json({
statusCode: err.statusCode,
message: err.message,
});
};
exports.errors = errors;
Create a middleware to validate object id
validateObjectId.js
const mongoose = require("mongoose");
const AppError = require("appError");
module.exports = function (req, res, next) {
const { _id } = req.params;
if (_id && !mongoose.Types.ObjectId.isValid(_id)) {
throw new AppError(422, "Invalid ID field in params");
}
next();
};
In your app.js
const { errors } = require("errors");
// At the end of all middlewares
// Error Handler Middleware
app.use(errors);
In your routes file
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const Artist = require("../models/Artist");
const loginRequired = require("../middleware/loginRequired");
const validateId = require("validateObjectId");
const {
getArtists,
addArtist,
getArtistById,
updateArtist,
deleteArtist,
} = require("../controllers/artistController");
// Your routes
router
.route("/:id")
.get(validateId, loginRequired, getArtistById) // Get an artist by their id
.put(validateId, loginRequired, updateArtist) // Update an artist by their id
.delete(validateId, loginRequired, deleteArtist); // Delete an artist by their id
module.exports = router;
Now regarding findById method being repeated i dont see anything bad in that as it is specific to database call still you can introduce a staic method on model itself or create a single method on cntroller but still need to check if it returns the found object or not and handle the error on that.

How do I query with url parameter?

I am new to Node.js and trying to check if an e-mail is already taken by sending the email as a url parameter from iOS app. It is not working, not sure what I am doing wrong.
I am unable to console.log the email parameter in VSCode sent from the front-end, it DOES print in XCODE ( http://localhost:3000/api/user/email/test#gmail.com ) and I know the backend is getting the GET request.
My router code is:
const express = require(`express`)
const router = new express.Router()
const User = require(`../models/user-model`) // import User model
router.get(`/api/user/email/:email`, async (req, res) => {
console.log(req.params) // does NOT print email: test#gmail.com
try {
const user = await User.findOne(req.params.email)
if (user) {
console.log(user._id)
res.send({ available: false })
} else {
res.send({available: true})
}
} catch {
res.status(404).send()
}
})
Thank you!
const express = require(`express`)
const app = new express();
app.get(`/api/user/email/:email`, async (req, res) => {
console.log(req.params) // does NOT print email: test#gmail.com
try {
// const user = await User.findOne(req.params.email)
const user = {_id:123};
if (user) {
console.log(user._id)
res.send({ available: false })
} else {
res.send({available: true})
}
} catch {
res.status(404).send()
}
})
app.listen(3000,function(){
console.log("running");
})
Editing this.. I dont have enough points to comment.. your route seems to be fine, maybe you are not telling your application to use this route, somewhere before starting your application you should have something like:
this.app = new express();
...
this.app.use('/api', MailRouter); //<=== Adding your required mail route
...
I use to split url one parte here (/api) and the other one in the router (/user/email/:email). I'm not sure how to do it by adding it fully to the router (Maybe '/' maybe '')

Can't get single category - NodeJs API

I working on my API for the E-commerce app in MERN. I have done a few things already, and now I am trying to get single category. There is no error on console, and I read the code a few times, but postman keeps throwing Cannot GET error. I would appreciate it if someone can tell me what's the deal with this.
The part for creating new category works just fine, also as similar code for getting one product Code:
Category.js Router
const express = require("express");
const router = express.Router();
const { create, categoryById, get } = require("../controllers/category");
const { requireSignin, isAuth, isAdmin } = require("../controllers/auth");
const { userById } = require("../controllers/user");
router.get("/category/:categoryId", get);
router.post("/category/create/:userId", requireSignin, isAuth, isAdmin, create);
router.param("categoryId", categoryById);
router.param("userId", userById);
Category.js Controller
const Category = require("../models/category");
const { errorHandler } = require("../helpers/dbErrorHandler");
exports.categoryById = (req, res, next, id) => {
Category.findById(id).exec((err, category) => {
if(err || !category) {
return res.status(400).json({
error: 'Category does not exist'
});
}
req.category = category;
next();
});
}
exports.create = (req, res) => {
const category = new Category(req.body);
category.save((err, data) => {
if (err) {
return res.status(400).json({
error: errorHandler(err)
});
}
res.json({ data });
});
};
exports.get = (req, res) => {
return res.json(req.category);
}

Next.js form works locally but not on live server

I have been implementing a Next.js app for a side project of mine. It is a basic brochure-style site with a contact form.
The form works perfectly fine when the site is run locally, however I have just published the site to Netlify and now when submitting a form I encounter the following error:
POST https://dux.io/api/form 404
Uncaught (in promise) Error: Request failed with status code 404
at e.exports (contact.js:9)
at e.exports (contact.js:16)
at XMLHttpRequest.d.(/contact/anonymous function) (https://dux.io/_next/static/cFeeqtpSGmy3dLZAZZWRt/pages/contact.js:9:4271)
Any help would be extremely appreciated!
This is my Form Submit function:
async handleSubmit(e) {
e.preventDefault();
const { name, email, option, message } = this.state;
const form = await axios.post('/api/form', {
name,
email,
option,
message
});
this.setState(initialState);}
This is my server.js file:
const express = require('express');
const next = require('next');
const bodyParser = require('body-parser');
const mailer = require('./mailer');
const compression = require('compression');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.use(compression());
server.use(bodyParser.json());
server.post('/api/form', (req, res) => {
const { email = '', name = '', option = '', message = '' } = req.body;
mailer({ email, name, option, text: message })
.then(() => {
console.log('success');
res.send('success');
})
.catch(error => {
console.log('failed', error);
res.send('badddd');
});
});
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(3000, err => {
if (err) throw err;
console.log('> Read on http://localhost:3000');
});
});
It looks like nextjs tries to render the /api/form page and you get a not found with that.
Please make sure you start the server with node server.js instead of next start.
What about try to use full endpoint http://~~~/api/form instead of just /api/form?
Or I think, you can solve this problem if you use process.env
const config = {
endpoint: 'http://localhost:8080/api'
}
if (process.env.NODE_ENV === 'production') {
config.endpoint = 'hostname/api'
}

Categories

Resources