HTML is being sent instead of JSON Data - json

I'm trying to retrieve data from a SQL database and display that said data on a Reactjs web app. However, all the calls I make to the database results in the HTML of the webpage in focus. I have set the headers, and I've tried to change the way the response from the express call is being handled.
Here is the expressjs script I am using right now:
const express = require('express');
const sql = require('mssql/msnodesqlv8');
const bodyParser = require('body-parser');
const path = require('path');
const cors = require('cors');
const db = require('./db.js');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use('/counselling/triageadmin/', express.static(path.join(__dirname, '/build')));
app.use(cors());
app.get('/getTable', function (req, res, next){
var request = new sql.Request(db);
request.query('select * from Counselling order by TicketID desc', (err, result) =>{
if (err) { return next(err); }
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result["recordset"]));
});
});
From there, my axios calls look like this:
componentWillMount(){
let self = this;
axios.get("/getTable")
.then(function (response){
console.log(response.data);
self.setState({
data: response.data,
});
})
.catch(function (error){
console.log(error);
})
}
I added the console.log to check what was being returned, and as said, it was the HTML code of the current page of focus.
I made some changes to reflect what steps I took to get the 500 issue out. The current code, however, results in a 404.

If you move your get on top of your put it should work. The problem seems to be that the static clause resolves your request before it gets to your endpoint, so if you do this:
app.get('/counselling/triageadmin/getTable', function (req, res, next){
var request = new sql.Request(db);
request.query('select * from Counselling order by TicketID desc', (err, result) =>{
if (err) { return next(err); }
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result["recordset"]));
});
});
app.use('/counselling/triageadmin/', express.static(path.join(__dirname, '/build')));
the path to the get will attempt to be matched before you're routed to your static files.
Ideally you would want to have your rest endpoints under a different namespace, i.e. /api but if you decide to keep your setup, this should help.

I think your routes might be conflicting with each other. From the express documentation at: http://expressjs.com/en/4x/api.html#app.use
// this middleware will not allow the request to go beyond it
app.use(function(req, res, next) {
res.send('Hello World');
});
// requests will never reach this route
app.get('/', function (req, res) {
res.send('Welcome');
});
Thus, your route '/counselling/triageadmin/getTable' will never be reached, because your route '/counselling/triageadmin/' is intercepting it, responding with static resources.
To solve this, try organizing your routes in a way that puts all of your API requests at a different subfolder, like '/api'. So your getTable endpoint would be located at: '/api/counselling/triageadmin/getTable/' or something like that.

I'm also learning the MEAN stack and I stumbled upon your question since I had the opposite problem. I wanted it to respond with an HTML instead of a JSON
this line of code MAKES it respond with an HTML
res.send(JSON.stringify(result["recordset"]));
(I tried res.send("<h3 HTML T_T </h3>");) and it did send and HTML
however, if you try
res.json(String(req.params.id)); <= Notice the res.json instead of res.send
It responds with a JSON :)
I hope this helped

Related

req.body is empty prototype in onRequest firebase cloud functions (With multer)

In my cloud function:
const app = express();
app.use(multer().array());
app.post("/", (req, res) => {
console.log("hit", req.body.from);
console.log("hit", req.body.from);
return res.sendStatus(200);
});
const emailInboundWebhook = functions.https.onRequest(app);
module.exports = {
emailInboundWebhook
}
I get this in logs:
i functions: Beginning execution of "emailInboundWebhook"
> hit undefined
> hit undefined
i functions: Finished "emailInboundWebhook" in ~1s
But when the same endpoint served as an express app(outside cloud functions):
const express = require("express");
const app = express();
const multer = require('multer');
app.get("/", async (req, res) => {
res.status(200).json({foo: "Bar"});
})
app.use(multer().array());
app.post("/webhook", async (req, res) => {
console.log("hit",req.body.to);
console.log("hit",req.body.from);
res.sendStatus(200);
});
app.listen(80, () => {
console.log("App listening on 80");
})
Gives this:
hit a#some-email-inbound.some.url
hit Rahul Priyadarsi <myemailid#gmail.com>
The two results are for same email sent and these functions are fired as sendgrid webhooks which send multipart/form-data POST requests that contain details of the email sent to a#some-email-inbound.some.url from myemailid#gmail.com
I have no idea as to why the two results are different(I am testing them via ngrok and since the console log lines run, clearly the function is hit).
I had the same problem.
Take a look in this issue: https://github.com/expressjs/multer/issues/572
Switch from Multer to Busboy, is also a good option.
One thing: In this situation use https.Request (from cloud-functions) instead of Request from express.

Require a file within a route to run a query

Im trying to set up my routes and then include a "content" file that would run a query
app.get('/participants', function(req, res, next) {
var participants = require('./content/participants');
});
and then the participants file:
const db = database.connect('olmsdb.1sserver.com', 'campyio');
db.raw('SELECT * FROM participants').then(function(results) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(results));
return results;
db.destroy();
});
The goal here is to hit the /participants route and then run the the select query and send the query results.
require() doesn't work like source(..) or execute in other languages. The code in it only execute once when first required. Then the module is cached.
You need to return functions and classes in a module file, using module.exports etc.
To do this:
participants.js:
const db = database.connect('olmsdb.1sserver.com', 'campyio');
exports.getParticipants = function() {
return db.raw('SELECT * FROM participants');
}
app.js:
var participants = require('./content/participants');
app.get('/participants', function(req, res, next) {
participants.getParticipants().then(function(results) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(results));
next();
});
});
You need to put that code in an exported function so that you can call it with the request & response every time you get a request.
That means there is no point in require()ing it inside your route handler.

How to display JSON file with Node.JS/Express

I'm VERY new to Node.js... so this is probably going to be stupid, basic. Here is what I am trying to do: I want to create a Node.js app that will query my MySQL database and return a JSON file to the user.
So far I have very little :) I have a project created with Webstorm. I have an index.js file and an index.ejs file. The index.js file has the following:
var express = require('express');
var router = express.Router();
var appdata = require('../data.json');
var mysql = require('mysql');
// http://nodejs.org/docs/v0.6.5/api/fs.html#fs.writeFile
var fs = require('fs');
var connection = mysql.createConnection({
host: 'xxxxxx',
user: 'xxxxx',
password: 'xxxxx'
database: 'xxxxx';
});
connection.connect();
router.get('/', function(request,response) {
connection.query('select AProgram_UID as UID, SiteDescription as Program, IcStatus as Status from AP_Details;', function (err, results, fields) {
if (err) {
console.log('Error in Query', err.message);
return response.send(500, err.message);
};
return JSON.stringify(results);
connection.end();
});
});
I haven't defined what goes in the index.ejs file because I really don't know where to go from here. I can write the JSON out to file from the code shown if I use writeFile, so I know the database part is correct.
Hopefully I explained enough... as mentioned, I'm new to Node. I just want to do something 'real' with it and this is something I need on a project I have.
Thanks!
In your router.get callback return the JSON back to the requester by using res.json to properly assign the Content-Type header to application/json and stringify whatever is passed to it.
Also you want to remove your return statements to before connection.end() otherwise connection.end() will never be called.
router.get('/', function(req, res) {
connection.query('select AProgram_UID as UID, SiteDescription as Program, IcStatus as Status from AP_Details;', function (err, results, fields) {
if (err) {
console.log('Error in Query', err.message);
res.status(500).send(err.message);
}
else
// render index view and pass in results JSON
res.json(results);
return connection.end()
});
});
Edit to use EJS View Engine Rendering
In order to use EJS you need to have your View Engine set to EJS and have a default Views directory setup. In your main Express server file it should look something like this before any routes
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
You'll need to change the code above from using res.json to use res.render. You'll also need to pass your results into the render function so the index.ejs can access the results JSON
res.render('index', { results: results });
In your index.ejs file you can access results using the EJS markup syntax
<html>
<body>
<p><% results %></p>
</body>
</html>

what's the best way to send a variable using method get with express, mysql and node.js

I'm building a web site using node.js express MySQL and boostrap, when I try to send a variable against method get for to do a query to the database, it's seem doesn't work, because there's no a good render. this is my code:
app.get('/reservaciones/leer/:id', function(req, res) {
var idreservacion = req.params.idreservacion;
crud.get_leer_reservacion(req,idreservacion,function(data_leer){
res.render'../views/leer.html',data:data_leer});
});
});
exports.get_leer_reservacion = function(req,idreservacion,fn){
// here the query
connection.query('select * from reservacion where idreservacion = '"+idreservacion+"'', function(err,rows){
if(err){
throw err;
}
return fn(rows);
});
};
https://drive.google.com/folderview?id=0BxFTEy90zOKAfmJOXzR3NDFLa081NUtEUFU4LWhuN2ZUTDMtVktPeHlYbVUzWW02a2pGWEk&usp=sharing
res.render'../views/leer.html',data:data_leer});
should be:
(outside of app.get:)
app.use('views', '../views');
(inside:)
res.render('leer',{data:data_leer});
If your problem is actually getting the templated data into the page I suggest the ejs npm package and templating system, you would use <%= data => to template in the value
In this code:
app.get('/reservaciones/leer/:id', function(req, res) {
var idreservacion = req.params.idreservacion;
You define a parameter called id, but you retrieve a parameter called idreservacion. Try something like this:
app.get('/reservaciones/leer/:id', function(req, res) {
var idreservacion = req.params.id;

passport send error by json

I'm making an app with express + passport and angularJS; I want to be able to send any errors produced from passport (such as username taken or no email provided) by json so my angularJS app can receive these errors in a json response. More specifically right now I want to have a json response to my signup POST method that outputs any errors. I have tried to do this for myself and I've search all over the web and stack overflow I just cannot work this out!
Here is my users route file in express:
var express = require('express');
var router = express.Router();
var isAuthenticated = require('../config/isAuthenticated');
module.exports = function(passport){
router.get('/loggedin', function(req, res){
res.send(req.isAuthenticated() ? req.user : '0');
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/',
failureRedirect : '/signup',
failureFlash: true
}));
router.post('/login', passport.authenticate('local-login'), function(req, res){
res.send(req.user);
});
router.post('/signout', function(req,res){
req.logout();
res.json({redirect: '/'});
});
router.get('/authtest', isAuthenticated, function(req, res){
res.render('authtest', {user: req.user});
});
return router;
};
This is my passport signup strategy:
passport.use('local-signup', new LocalStrategy({
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password, done){
process.nextTick(function(){
User.findOne({'local.username' : username}, function(err, user){
if(err) return done(err);
if (user) { //username already exists
return done(null, false, {message: 'Username already exists'});
} else if(!req.body.email) { //no email address provided
return done(null, false, {message: 'You must provide an email address!'});
} else {
var newUser = new User();
newUser.local.username = username;
newUser.generateHash(password, function(err, hash){
if(err) return done(err);
newUser.local.password = hash;
});
newUser.email = req.body.email;
newUser.servers = [];
newUser.save(function(err){
if(err) throw err;
return done(null, newUser);
});
};
});
});
}
));
I know looking at my code right now it looks like I haven't tried to solve this myself at all but this is just my latest working code; I have been stuck at this for the past few days!
Any help would be greatly appreciated :)
According to the current code of passport this is probably achievable by passing custom callback to handle all results of authentiction yourself. This callback is given after options or instead of those.
passport( "local-signup", { ... }, callbackFn );
or
passport( "local-login", callbackFn );
This callback is used in all resulting situations of trying to authenticae. It is thus invoked on processing errors like this:
callbackFn( err )
If (all configured) authentications have failed it is called with
callbackFn( null, false, challenge(s), status(es) )
On successfully having authenticated user the callback is invoked like so:
callbackFn( null, user, infos )
with infos optionally provided by strategies.
Now comes the bottom-side: In either situation passport.authenticate() skips usual processing but instantly invokes provided callback to care for the rest. This includes processing of any options passed in call for passport.authenticate() like flashing messages, preparing session and request for containing authenticated user etc.
Since options given passport.authenticate() are never passed into callback there is actually no obvious reason to use both.
When I was stumbling over the very same problem (linking passport-service with angular-js POST request) I declined to consider use of callback a proper solution. This callback isn't documented. And it doesn't even look quite useful for it isn't passing req, res and next to pass any actual request in callback. Thus it makes very little sense to use it at all and I'd expect it to vanish soon or to change its behaviour quite much.
So the second approach was about trying to figure out why there is a problem in AngularJS. Passport is sending plain text Unauthorized in response with status code 401. AngularJS is trying to parse this as JSON and produces Syntax error. The text Unauthorized results from passprt ending response very simply by invoking
res.statusCode = 401;
res.end(http.STATUS_CODES[res.statusCode]);
Thus a proper workaround might try to replace
either text in http.STATUS_CODES though this is having impact on processing further requests and thus isn't preferrable
or res.end() by an overloaded method acting differently if res.statusCode is 401.
Due to affecting any current request, only, I tried the latter. Replaced res.end() might be used to send any text you want:
router.post('/login',
function(req, res, next) {
var _end = res.end;
res.end = function() {
if (res.statusCode === 401) {
return _end('{"status":"Unauthorized"}');
}
return _end.apply(this, arguments);
};
next();
},
passport.authenticate('local-login'),
function(req, res) {
res.send(req.user);
}
);
Alternatively the replaced method might add previously missing response header information on content type, for this was actually causing issues in AngularJS processing that response as JSON by default.
router.post('/login',
function(req, res, next) {
var _end = res.end;
res.end = function() {
if (res.statusCode === 401) {
res.set("Content-Type", "text/plain");
}
return _end.apply(this, arguments);
};
next();
},
passport.authenticate('local-login'),
function(req, res) {
res.send(req.user);
}
);
Finally, either approach is really just a workaround. I think passport is in the need for revising this annoying limitation.