Get Query Params in express node js - node.js

The url contains all the query strings after the # key
http://localhost:3002/callback#access_token=nQevH_hZSjs3qdOoLNnAIITwqd3lCdkq&expires_in=7200&token_type=Bearer
how do we access the params after #

var url = 'http://localhost:3002/callback#access_token=nQevH_hZSjs3qdOoLNnAIITwqd3lCdkq&expires_in=7200&token_type=Bearer';
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\#&]' + name + '=([^&#]*)');
var results = regex.exec(url);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
console.log(getUrlParameter('access_token'));
console.log(getUrlParameter('expires_in'));
console.log(getUrlParameter('token_type'));

Best practice is to use ? instead of #
So your url should be
http://localhost:3002/callback?access_token=nQevH_hZSjs3qdOoLNnAIITwqd3lCdkq&expires_in=7200&token_type=Bearer
Now you can get the query params with below method
var express = require('express');
var app = express();
app.get('/callback', function(req, res){
console.log('access_token: ' + req.query.access_token);
console.log('expires_in: ' + req.query.expires_in);
console.log('token_type: ' + req.query. token_type);
});
app.listen(3000);

Anything after the # isn't sent to the server by the browser.. you can
only parse it if the url is generated or obtained from the server. Then you can use nodes in-built url module to parse symbols in the url

You can use the substring() method:
EDIT: the string you can get from response.body. You have to use body-parser or express.json
let str = "http://localhost:3002/callback#access_token=nQevH_hZSjs3qdOoLNnAIITwqd3lCdkq&expires_in=7200&token_type=Bearer";
let index=str.indexOf("#");
let res = str.substring(index+1);
Output:
$ node server.js
access_token=nQevH_hZSjs3qdOoLNnAIITwqd3lCdkq&expires_in=7200&token_type=Bearer

Related

Chart.js with Node.js

Assume that I want to make a bar chart in HTML. I use node.js as a backend and get data from the database through node.js. I usually will render the data to view into ejs files. Is it possible for me to use database data from node.js then pass it to javascript (client-side) where I am creating the chart.js?
Try this: replace result with your data!
const fs = require('fs');
var express = require('express');
var app = express();
var path = require('path');
var Chart = require('chart.js');
var result =[3,6,9];
app.get('/', function(req, res){
let _resLine = '<h1>Ereignisse: ' + result+'</h1>';
console.log('show chart:');
console.log(_resLine);
_html = "<script src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js'></script>"+
"<canvas id='bar-chart' width='800' height='450'></canvas>"+
"<script>"+
"var logChart = new Chart(document.getElementById('bar-chart'), {"+
"type: 'horizontalBar',"+
"data: {"+
"labels: ['Ereignis1', 'Ereignis2', 'Ereignis3'],"+
"datasets: ["+
"{"+
"label: 'Aufrufe',"+
"backgroundColor: ['#3e95cd', '#8e5ea2','#3cba9f'],"+
"data: ["+result[0]+","+result[1]+","+result[2]+"]"+
"}"+
"]"+
"},"+
"options: {"+
"legend: { display: false },"+
"title: {"+
"display: true,"+
"text: 'Ereignisse '"+
"}"+
"}"+
"});"+
"</script>";
res.send(_html);
});
app.listen(3005);
cmd: node showChart.js
URLs:
http://localhost:3005
See also example in my git archive

JSONSerialization makes incorrect JSON object. Swift

I'm creating an iOS app that connects to a NodeJS server. The get method works fine but the POST method has problems.
var urlRequest = URLRequest(url: "http://localhost:3000/register")
urlRequest.httpMethod = "POST"
let info: [String:Any] = ["username": "username", "password":"username", "email":"username#username.com"]
do {
let jsonInfo = try
JSONSerialization.data(withJSONObject: info, options[])
urlRequest.httpBody = jsonInfo
} catch {
print("ERROR")
return
}
The request gets sent but something goes wrong with JSONSerialization because this is the JSON data that the server gets:
{'{"email":"username#username.com","username":"username","password":"username"}': '' }
This is what I'm going for:
{"email":"username#username.com","username":"username","password":"username"}
This is part of the server code:
const express = require('express');
const bodyParser = require('body-parser');
var app = express();
var allowMethods = function(req, res, next) {
res.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE');
next();
}
http.createServer(app).listen(3001);
console.log("Server started");
app.use(bodyParser.urlencoded({extended: true}));
app.use(allowMethods);
const _ = require('lodash');
let b = _.pick(req.body, ['username', 'password', 'email']);
Any ideas on what I'm doing wrong? I'd like to avoid using alamofire if possible. I've tried changing the format of the dictionary but always turns out as:
{ 'the whole dictionary is the key': ''}
I've also tried using pretty print and this was the result:
{ '{\n "email" : "username#username.com",\n "username" : "username",\n "password" : "username"\n}': '' }
Any help is appreciated. Thank you!
EDIT:
I tried Mike Taverne's suggestions.
I changed the server code to use this instead:
app.use(bodyParser.json());
But I receive an empty body from the simulator.
I also added these to the swift code:
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
But the server also receives an empty body and by empty body I mean the data I'm trying to send is received as empty by the server. When I check the httpBody the data is there but for some reason the server doesn't receive it.
I believe your Swift code is fine. When I did this in a playground:
print(String(data: urlRequest.httpBody!, encoding: String.Encoding.utf8)!)
It printed:
{"username":"username","password":"username","email":"username#username.com"}
I'm not an expert on body-parser, but I think that instead of this:
bodyParser.urlencoded({extended: true})
You should be using this:
bodyParser.json([options]) //not sure which options exactly you need
You may need to set Content-Type: application/json header as well. Refer to the body-parser documentation for more info.
I solved it by changing the data itself. Instead of forcing it to pass JSON I passed it as a string encoded using UTF8
let dataString = "username=username&password=username&email=username#username.com"
urlRequest.httpBody = dataString.data(using: .utf8)
I got the answer by using the method in this post:
HTTP Request in Swift with POST method

url.searchParams returns undefined in node.js

In the following node.js example:
var url = require('url');
var urlString='/status?name=ryan'
var parseObj= url.parse(urlString);
console.log(urlString);
var params = parseObj.searchParams;
console.log(JSON.stringify(params));
the property searchParams is undefined. I would expect searchParams to contain the parameters of the search query.
As you see in https://nodejs.org/dist/latest-v8.x/docs/api/url.html#url_class_urlsearchparams
searchParams is a proxy to an URL object. You must obtain a new URL complete object (with domain and protocol) and then you can use searchParams:
var url = require('url');
var urlString='https://this.com/status?name=ryan'
var parseObj= new url.URL(urlString);
console.log(urlString);
var params = parseObj.searchParams;
console.log(params);
Other way is using the query attribute (you must pass true as second parameter to url.parse):
var urlString='/status?name=ryan'
var parseObj= url.parse(urlString, true);
console.log(parseObj);
var params = parseObj.query;
console.log(params);
It is recommended to use: var parsedUrl = new URL(request.url, 'https://your-host'); instead of url.parse
url.parse shouldn't be used in new applications. It is deprecated and could cause some security issues: as stated here

Parsing Get HTTP Request for parameters and using in http response

I am trying to learn node.js. Here is the basic hello World example where I expect a http request like
http://localhost:3000?fname=ABC&lname=XYZ
And return response to print on the browser
Hello, ABC XYZ!
This is working fine. But if you see the response.end function I have something like query.lname || "Anonymous". I was expecting that in case the lname is not specified in the URL then the response contains 'Anonymous' in place of last name. But this doesn't happen and I get
Hello, ABC undefined!
The code is as follows. Kindly help me understand this. Thanks for the help.
var http = require('http');
var url = require('url');
var querystring = require('querystring');
http.createServer(function(request, response) {
var query = querystring.parse(url.parse(request.url).query || "");
response.writeHead(200,{’content-type’:"text/plain"});
response.end("Hello, "+(query.fname+" "+ query.lname || "Anonymous")+"!\n");
}).listen(3000);

nodejs web root

I was under the impression that when you run a nodejs webserver the root of the web is the folder containing the js file implementing the webserver. So if you have C:\foo\server.js and you run it, then "/" refers to C:\foo and "/index.htm" maps to C:\foo\index.htm
I have a file server.js with a sibling file default.htm, but when I try to load the contents of /default.htm the file is not found. An absolute file path works.
Where is "/" and what controls this?
Working up a repro I simplified it to this:
var fs = require('fs');
var body = fs.readFileSync('/default.htm');
and noticed it's looking for this
Error: ENOENT, no such file or directory 'C:\default.htm'
So "/" maps to C:\
Is there a way to control the mapping of the web root?
I notice that relative paths do work. So
var fs = require('fs');
var body = fs.readFileSync('default.htm');
succeeds.
I believe my confusion arose from the coincidental placement of my original experiment's project files at the root of a drive. This allowed references to /default.htm to resolve correctly; it was only when I moved things into a folder to place them under source control that this issue was revealed.
I will certainly look into express, but you haven't answered my question: is it possible to remap the web root and if so how?
As a matter of interest this is server.js as it currently stands
var http = require('http');
var fs = require('fs');
var sys = require('sys');
var formidable = require('formidable');
var util = require('util');
var URL = require('url');
var QueryString = require('querystring');
var mimeMap = { htm : "text/html", css : "text/css", json : "application/json" };
http.createServer(function (request, response) {
var body, token, value, mimeType;
var url = URL.parse(request.url);
var path = url.pathname;
var params = QueryString.parse(url.query);
console.log(request.method + " " + path);
switch (path) {
case "/getsettings":
try {
mimeType = "application/json";
body = fs.readFileSync("dummy.json"); //mock db
} catch(exception) {
console.log(exception.text);
body = exception;
}
break;
case "/setsettings":
mimeType = "application/json";
body="{}";
console.log(params);
break;
case "/":
path = "default.htm";
default:
try {
mimeType = mimeMap[path.substring(path.lastIndexOf('.') + 1)];
if (mimeType) {
body = fs.readFileSync(path);
} else {
mimeType = "text/html";
body = "<h1>Error</h1><body>Could not resolve mime type from file extension</body>";
}
} catch (exception) {
mimeType = "text/html";
body = "<h1>404 - not found</h1>" + exception.toString();
}
break;
}
response.writeHead(200, {'Content-Type': mimeType});
response.writeHead(200, {'Cache-Control': 'no-cache'});
response.writeHead(200, {'Pragma': 'no-cache'});
response.end(body);
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');
I'm not completely certain what you mean by "routes" but I suspect that setsettings and getsettings are the sort of thing you meant, correct me if I'm wrong.
Nodejs does not appear to support arbitrary mapping of the web root.
All that is required is to prepend absolute web paths with a period prior to using them in the file system:
var URL = require('url');
var url = URL.parse(request.url);
var path = url.pathname;
if (path[0] == '/')
path = '.' + path;
While you're correct that the root of the server is the current working directory Node.js won't do a direct pass-through to the files on your file system, that could be a bit of a security risk after all.
Instead you need to provide it with routes that then in turn provide content for the request being made.
A simple server like
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
Will just capture any request and respond in the same way (but doesn't read the file system).
Now if you want to serve out file contents you need to specify some way to read that file into the response stream, this can be done a few ways:
You can use the fs API to find the file on disk, read its contents into memory and then pipe them out to the response. This is a pretty tedious approach, especially when you start getting a larger number of files, but it does allow you very direct control over what's happening in your application
You can use a middleware server like express.js, which IMO is a much better approach to do what you're wanting to do. There's plenty of questions and answers on using Express here on StackOverflow, this is a good example of a static server which is what you talk about
Edit
With the clarification of the question the reason:
var body = fs.readFileSync('/default.htm');
Results in thinking the file is at C:\default.htm is because you're using an absolute path not a relative path. If you had:
var body = fs.readFileSync('./default.htm');
It would then know that you want to operate relative to the current working directory. / is from the root of the partition and ./ is from the current working directory.

Resources