Can't catch the URL parameters with ExpressJS - node.js

I'm trying to capture the parameter values from the callback URL coming from the Fitbit API.
The call back URL looks like below,
http://localhost:9000/callback#access_token=********&user_id=*******&scope=sleep+settings+nutrition+activity+social+heartrate+profile+weight+location&token_type=Bearer&expires_in=30418415
I have stated by callback URL in the fitbit API as http://localhost:9000/callback.
My ExpressJS code is as below.
const express = require('express');
const morgan = require('morgan');
const path = require('path');
const app = express();
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms'));
app.use(express.static(path.resolve(__dirname, '..', 'build')));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
const PORT = process.env.PORT || 9000;
app.get('/callback', function(req, res) {
var access_token = req.param('access_token') || null;
var user_id = req.param('user_id') || null;
res.send(access_token + ' ' + user_id);
});
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}!`);
});
I can't figure out where the problem is.

The # symbol in an URL is to introduce framgent identifier. So your callback url http://localhost:3000/callback#access_token=********&user_id=*******&scope=sleep+settings+nutrition+activity+social+heartrate+profile+weight+location&token_type=Bearer&expires_in=30418415 will only get the http://localhost:3000/callback not sending any parameters to your server. So, you can not get these parameters in your server directly.
However there is solution to this. Please refer to this answer.

req.param('token') is depreciated use req.params.token pass the value directly into the url
if you are using req.params specify you key params in the url
app.get('/callback/:access_token/:user_id', function(req, res) {
//url ==> localhost:9000/callback/1233/123
var access_token = req.params.access_token || null;
var user_id = req.params.user_id || null;
console.log(req.params)
res.send(access_token + ' ' + user_id);
});
if you want the catch the value in the url means use req.query instead of req.params pass the value using the key of req.query
app.get('/callback',function(req, res) {
var access_token = req.query.access_token || null;
var user_id = req.query.user_id || null;
console.log(req.query);
res.send(access_token + ' ' + user_id);
});

Related

Returning data to a user from an external API

i am trying to return the value of my search after using the node-spotify-api package to search for an artist.when i console.log the spotify.search ..... without the function search function wrapped around it i get the values on my terminal..what i want is when a user sends a request to the userrouter routes i want is to display the result to the user..i using postman for testing ..
This is the controller
const Spotify = require('node-spotify-api');
const spotify = new Spotify({
id: process.env.ID,
secret: process.env.SECRET,
});
const search = async (req, res) => {
const { name } = req.body;
spotify.search({ type: 'artist', query: name }).then((response) => {
res.status(200).send(response.artists);
}).catch((err) => {
res.status(400).send(err);
});
};
module.exports = {
search,
};
**This is the route**
const express = require('express');
const searchrouter = express.Router();
const { search } = require('./spotify');
searchrouter.route('/').get(search);
module.exports = searchrouter;
**This is my server.js file**
const express = require('express');
require('express-async-errors');
const app = express();
require('dotenv').config();
// built-in path module
const path = require('path');
// port to be used
const PORT = process.env.PORT || 5000;
// setup public to serve staticfiles
app.use(express.static('public'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.set('port', PORT);
const searchrouter = require('./route');
app.use('/search', searchrouter);
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'index.html'));
});
app.listen(PORT, (req, res) => {
console.log(`Server is listening on port ${PORT}`);
});
[that is my project structure][1]
Well Your Code has a bug
Which is
searchrouter.route('/').get(search);
You are using a get request and still looking for a req.body
const { name } = req.body;
name is going to equal to = undefined
and when this runs
spotify.search({ type: 'artist', query: name })
it's going to return an empty object or an error
req.body is empty for a form GET request
So Your fix is
change your get request to a post
searchrouter.route('/').post(search);

Cors request did not succeed when im trying to run it on another pc

so im developing website using nodejs, and then deploying it to microsoft azure, and using Azure Database for mysql server to be exact, and importing my databse using mysql workbench, now the problem is in the CORS, everyhting going well i run it on chrome and firefox in the same pc works fine, but when i try to acces the website using another pc, i get the error says "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3000/data/price%20asc. (Reason: CORS request did not succeed)".
heres my nodejs code:
//use path module
const path = require("path");
//use express module
const express = require("express");
//use hbs view engine
// const hbs = require('hbs');
//use bodyParser middleware
const bodyParser = require("body-parser");
//use mysql database
const mysql = require("mysql");
const app = express();
const db = require("./database");
//cors
const cors = require("cors");
// app.use(cors());
// app.use(
// cors({
// origin: "*",
// })
// );
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
//konfigurasi koneksi
const conn = mysql.createConnection({
// host: 'localhost',
// user: 'root',
// password: '',
// database: 'domdom'
host: "domdom.mysql.database.azure.com",
user: "domdom#domdom",
password: "Banana123",
database: "schema1",
port: 3306,
ssl: true,
});
//connect ke database
conn.connect((err) => {
if (err) throw err;
console.log("Mysql Connected...");
});
//set views file
app.set("views", path.join(__dirname, "/"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.json());
app.use(express.static(__dirname));
app.param("productname", function (request, response, next, product) {
// ... Perform database query and
// ... Store the user object from the database in the req object
request.product = product;
return next();
});
app.param("sort", function (request, response, next, price) {
// ... Perform database query and
// ... Store the user object from the database in the req object
request.price = price;
return next();
});
app.param("id", function (request, response, next, id) {
// ... Perform database query and
// ... Store the user object from the database in the req object
request.id = id;
ß;
return next();
});
//get all data
app.get("/data/:sort", (req, res) => {
let sql = "SELECT * FROM products Order By " + req.price;
let query = conn.query(sql, (err, results) => {
res.json(results);
});
});
//untuk search and sort
app.get("/data/:productname/:sort", function (req, res) {
let sql =
"SELECT * FROM products WHERE name like '%" +
req.product +
"%' Order By " +
req.price;
let query = conn.query(sql, (err, results) => {
res.json(results);
});
});
//untuk save data
app.post("/save/:id", (req, res) => {
let sql =
"INSERT INTO cart SELECT * from products WHERE id = '" + req.id + "'";
let query = conn.query(sql, (err, results) => {
if (err) throw err;
res.redirect("/");
});
});
//render interface
app.get("/", (req, res) => {
res.render("index");
});
//server listening
app.listen(3000, () => {
console.log("Server is running at port 3000");
});
as you can see in the code i have tried 3 ways trying to solve this problem, but nothing works, please help.
If you are using Azure app service to host your nodejs app,the most fastest way to config CORS on Azure Portal => app service => CORS :
I did some test on my side and this is my nodejs server code(as you can see, no config for CORS) :
const express = require('express')
const app = express()
const port = process.env.PORT || 8080
app.use(express.json())
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.post('/', (req, res) => {
var body = req.body;
res.send(`Hello ${body.name}!`)
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Test HTTP request from an local static web page:
<!DOCTYPE html>
<html>
<body>
<h1>The XMLHttpRequest Object</h1>
<button type="button" onclick="loadDoc()">Request data</button>
<p id="demo"></p>
<script>
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("POST", "https://nodeweb05.azurewebsites.net/", true);
xhttp.setRequestHeader("Content-type", "application/json");
var body = {"name":"testuser"};
xhttp.send(JSON.stringify(body));
}
</script>
</body>
</html>
You can try it yourself.
If you want to config CORS on code level, just try the config below:
const express = require('express')
const app = express()
var cors = require('cors')
app.use(cors())

Unable to make app.post working using nodeJs

I am trying to connect my Angular2 to my nodeJs server. I have an authentication form which makes a post request. And I would like to use node to handle the post request.
But so far I am unable to make my post request working. The console.log doesn't display anything.
What I am missing?
This is my server.js which points to the folder dist in which i made the build of angular.
const express = require('express');
const path = require('path');
const http = require('http');
var walker = require('node-sync-walker');
const bodyParser = require('body-parser');
// Get our API routes
const api = require('./server/routes/api');
var app = express();
// Parsers for POST data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Point static path to dist
app.use(express.static(path.join(__dirname, 'dist')));
// Set our api routes
app.use('/api', api);
// Catch all other routes and return the index file
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
walker.routeWalker(__dirname + '/server/routes', app);
/**
* Get port from environment and store in Express.
*/
const port = process.env.PORT || '3000';
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port, () => console.log(`API running on localhost:${port}`));
This is my api.js
var users = [{username: "user", password: "password"}];
var router = require('express').Router();
module.exports = function(app) {
router.post('/api/authenticate',
function(req, res) {
console.log("print something");
let params = JSON.parse(req.body);
// find if any user matches login credentials
let filteredUsers = users.filter(user => {
return user.username === params.username && user.password === params.password;
});
if (filteredUsers.length) {
res.sendStatus(200);
} else {
console.log("print something else");
return res.sendStatus(400)
}
//return;
});
}
You are configuring the route as '/api/api/authenticate'
You should remove '/api' from routes in api.js
Finally, it worked! I removed the api in /api/authenticate as #catalacs suggested. Then I changed how I import the module router from api.js to server.js.
server.js
var users = [{username: "test", password: "test"}];
var router = require('express').Router();
router.post('/authenticate',
function(req, res) {
console.log("print something");
let params = JSON.parse(req.body);
// find if any user matches login credentials
let filteredUsers = users.filter(user => {
return user.username === params.username && user.password === params.password;
});
if (filteredUsers.length) {
res.sendStatus(200);
} else {
console.log("print something else");
return res.sendStatus(400)
}
//return;
});
module.exports = router;
And in my server.js, I commented out this line:
walker.routeWalker(__dirname + '/server/routes', router);

How to configure express js 4 to serve some pages in http and others in https?

Is there any way to configure a node js application with express js 4 to serve some pages under http protocol and other, those which need more security, in https?
I describe my problem: I'm developing a shop online and I want to display certain pages, like the products list or the product detail views under http, and others which I think need more security, like login or the shopping cart views, under https protocol.
I have tried the express-force-ssl module, but it isn't working. The following code snippet is not from my app (which is too dirty) it is just an example which alos doesn't work for me:
var express = require('express');
var forceSSL = require('express-force-ssl');
var fs = require('fs');
var http = require('http');
var https = require('https');
var ssl_options = {
key: fs.readFileSync('./server-private-key.pem'),
cert: fs.readFileSync('./server-certificate.pem'),
ca: fs.readFileSync('./server-certificate-signing-request.pem')
};
var app = express();
var server = http.createServer(app);
var secureServer = https.createServer(ssl_options, app);
app.use(forceSSL);
app.get('/', function (req, res, next) {
res.send('Hello')
});
app.get('/user/:name', function (req, res, next) {
var user = req.params.name;
res.send('Hello ' + user + '')
});
app.get('/login', forceSSL, function (req, res, next) {
res.send('Hello<br/>Goodbye')
});
app.get('/logout', forceSSL, function (req, res, next) {
res.send('Hello')
});
secureServer.listen(443)
server.listen(8085)
console.log('server started');
The result is that when I launch the application, with url http://localhost:8085, the server automatically redirects it to https://localhost and serves all pages in https protocol.
What I want is to start on http://localhost:8085, navigate to http://localhost/user/userA, then from it go to https://localhost/login and, if click on "Hello" link, I would like to be redirected to http://localhost:8085.
Is there any missing code to get the behavior I want or even any other way to reach it without express-force-ssl module?
I have asked to the author of express-force-ssl module and he has told me that the redirect behavior works as expected. Here is the post.
But diving a little more in its code I've created a custom plugin to solve my problem. Here is the code:
var parseUrl = require('url').parse;
var isSecure = function (req) {
if (req.secure) {
return true;
}
else if (
req.get('X-Forwarded-Proto') &&
req.get('X-Forwarded-Proto').toLowerCase &&
req.get('X-Forwarded-Proto').toLowerCase() === 'https') {
return true;
}
return false;
};
exports = module.exports = function (req, res, next) {
if (isSecure(req)) {
if (req.method === "GET") {
var httpPort = req.app.get('httpPort') || 80;
var fullUrl = parseUrl(req.protocol + '://' + req.header('Host') + req.originalUrl);
res.redirect('http://' + fullUrl.hostname + ':' + httpPort + req.originalUrl);
}
else {
next();
}
}
else {
next();
}
};
It's very similar to force-ssl file but here we manage the opposite action, i.e., here I redirect to http when a route is forced to it. So it's needed to add the function to every route we want to see under http protocol:
var express = require('express');
var forceSSL = require('express-force-ssl');
var fs = require('fs');
var http = require('http');
var https = require('https');
var useHttp = require('./useHttp');
var ssl_options = {
key: fs.readFileSync('./server-private-key.pem'),
cert: fs.readFileSync('./server-certificate.pem')
};
var app = express();
var server = http.createServer(app);
var secureServer = https.createServer(ssl_options, app);
app.get('/', useHttp, function (req, res, next) {
res.send('Hello')
});
app.get('/user/:name', useHttp, function (req, res, next) {
var user = req.params.name;
res.send('Hello ' + user + '')
});
app.get('/login', forceSSL, function (req, res, next) {
res.send('Hello<br/>Goodbye')
});
app.get('/logout', forceSSL, function (req, res, next) {
res.send('Hello')
});
app.set('httpsPort', 9090);
app.set('httpPort', 8085);
secureServer.listen(9090)
server.listen(8085)
console.log('server started');
As you can see I need now to specify in all routes which protocol use: useHttp for http or forceSSL for https.
Although I'm not comfortable at all with this solution because I have to specify in all routes which kind of protocol I want. But at least it works. So I would be very pleased if someone finds any other solution, for isntance, adding in middleware layer a function to manage all http requests and just redirect to https when it is specified with forceSSL. By the moment, this works.

express session management not working

I am new to the node.js world. I am trying to write a REST services and I am stuck with session management. So I created a separate app just to see if I can get the session to work, but it doesn't, here is the code. The req.session.username is always undefined:
var express = require('express');
var url = require('url');
var app = express()
app.use(express.cookieParser('Hiren'))
app.use(express.session({ secret: 'HirenAdesara' }))
app.use(express.bodyParser())
app.use(app.router)
//Sniff HTTP
app.all('*', function(req, res, next) {
//Check for Authentication
console.log(req.session)
if ((!(/^\/auth/g.test(req.url))) && (!req.session)) {
console.log('in app.all: Unauthorized')
res.send(401)
}
else
{
return next()
}
})
app.post('/auth', function(req, res) {
var query = req.body
console.log('Query' + JSON.stringify(query))
username = query.username;
password = query.password;
if(username == 'Hiren' && password == 'Adesara')
{
req.session.username = 'Hiren';
console.log('New Session Created..')
res.send(200)
}
else
{
console.log('New session could not be created.')
res.send(401)
}
})
app.get('/projects', function(req,res) {
console.log('inside projects' + req.session.username);
res.send(req.session.username); })
app.listen(2048)
console.log('Listening on port 2048...')
It doesn't work and I have no idea what is wrong here.
Star by moving the 3 lines in your app.get('/'...) outside of it:
var express = require('express');
var querystring = require('querystring');
var app = express()
app.use(express.cookieParser('Hiren')); // This line
app.use(express.session({ secret: 'HirenAdesara' })); // This line
app.use(express.bodyParser()); // This line
app.get('/', function(req, res){
res.send('hello from the root page');
})
// the rest of your code

Resources