Relative uri for node.js request library - javascript

I have the following code, and node.js can't resolve the url:
const request = require('request')
const teamURL = `/users/${user._id}/teams`;
const req = request({
url: teamURL,
json: true
},
function(error, response, body) {
if (!error && response.statusCode == '200') {
res.render('userHome.html', {
user: user,
teams: body
});
}
else {
console.error(error);
next(error);
}
});
is there a good way to use relative paths/urls with the request library on a server-side node.js Express app?

Giving just a relative url only works if it is clear from context what the root part of the url should be. For instance, if you are on stackoverflow.com and find a link /questions, it's clear from context the full url should be stackoverflow.com/questions.
The request library doesn't have this kind of context information available, so it needs the full url from you to do be able to make the request. You can build the full url yourself of course, for instance by using url.resolve():
var url = require('url');
var fullUrl = url.resolve('http://somesite.com', '/users/15/teams');
console.log(fullUrl); //=> 'http://somesite.com/users/15/teams');
But of course this will still require you to know the root part of the url.

Jasper 's answer is correct -- the request module needs full URL. if you are in a situation where you have a single page application, with lots of requests to an API with the same base URL, you can save a lot of typing by creating a module like this:
var url = require('url');
var requestParser = (function() {
var href = document.location.href;
var urlObj = url.parse(href, true);
return {
href,
urlObj,
getQueryStringValue: (key) => {
let value = ((urlObj && urlObj.query) && urlObj.query[key]) || null;
return value;
},
uriMinusPath: urlObj.protocol + '//' + urlObj.hostname
};
})();
then, to grab the base URL anytime you need it: requestParser.uriMinusPath
and grab the value of an arbitrary query parameter: RequestParser.getQueryStringValue('partner_key');

Related

URL transformation in Chrome javascript bookmarklet showing "undefined"

I'm trying to create a Chrome bookmarklet that will take a part of the pathname from one URL and navigate to a new URL using that variable as a parameter (the variable is 1234567 in the example below).
From: 'https://example.com/reporting-dashboard/#/dashboard/1234567?pageId=Page_3a7c73c6-34c9-4ab3-8d1f-5bd437c07115'
To: 'https://example.com/tool/permissions/resources?namespace=1234567'
The hostname differs depending on the environment I'm working in but will always stay the same when I transform it with the bookmarklet so I'm trying to pull that info when I compose the new URL. This is what I've got so far, but I keep getting "undefined" in the transformed URL (below) when I run the code. Any ideas on what I've got wrong here?
'https://example.com/tool/permissions/resources?namespace=undefined'
My code:
//Sample URL: https://example.com/reporting-dashboard/#/dashboard/1234567?pageId=Page_3a7c73c6-34c9-4ab3-8d1f-5bd437c07115
var pathArray = location.pathname.split('/');
let secondLevelLocation = pathArray[3];
var newUrl = location.protocol + '//' + location.hostname + '/tool/permissions/resources?namespace=' + secondLevelLocation;
var w=window.open();w.location=newUrl;w.document.close();
In the code you've shown, there is an assumption that the URL hash (fragment identifier) will be included when accessing the pathname:
//Sample URL: https://example.com/reporting-dashboard/#/dashboard/1234567?pageId=Page_3a7c73c6-34c9-4ab3-8d1f-5bd437c07115
var pathArray = location.pathname.split('/');
let secondLevelLocation = pathArray[3];
This is where the problem occurs. In a URL, the pathname ends when one of the following characters are first encountered:
? (which begins the query string), or
# (which begins the fragment identifier)
The format of the hash / fragment identifier portion of the URL in your example is that of a fully-resolved URL without the origin (starting at the pathname).
Using this knowledge, you can use the native URL class to help you select the desired part of the input URL, then use it again to construct the target URL, as shown in the code below. Once you have the target URL, you can use it to navigate, etc.
function parseNamespace (url) {
const fragment = url.hash.slice(1);
if (!fragment.startsWith('/')) throw new Error('Path fragment not found');
url = new URL(fragment, url);
const namespace = url.pathname.split('/').at(-1);
return namespace;
}
function createUrl (address = window.location.href) {
let url = new URL(address);
const namespace = parseNamespace(url);
const pathname = '/tool/permissions/resources';
url = new URL(pathname, url.origin);
url.searchParams.set('namespace', namespace);
return url;
}
const url = createUrl('https://example.com/reporting-dashboard/#/dashboard/1234567?pageId=Page_3a7c73c6-34c9-4ab3-8d1f-5bd437c07115');
// You can omit the argument when you want to get the address from the current document:
// const url = createUrl();
console.log(url.href); // "https://example.com/tool/permissions/resources?namespace=1234567"

Missing responseJSON in jquery ajax Response

I'm working on a small web framework to run a HCI study in and came across the following problem:
I have a Node server running with express to serve my local host data from JSON files. Not the best db but since it's a single user system (only one participant will ever be using the system at any time) it really didn't make sense to add any other technology. The following Get request code works just fine:
function getUser(id,last) {
return $.ajax({
type: "GET",
url: "/data/user/"+id,
async: false
}).responseJSON;
}
Which is handled by the following node code:
app.get('/data/:asset/:id', function (req, res) {
var accJSN
res.setHeader('Content-Type', 'application/json');
if(req.params.asset === "user")
{
accJSN = JSON.parse(fs.readFileSync(path.join(__dirname,'/public/data/users.json')));
res.send(JSON.stringify(accJSN.users[req.params.id]));
}
The above code produces a response which I can use/print and contains the responseJSON attribute. The following code does not, I'll note the node code is in the same server.js file and the functions with jquery/ajax calls are in my client page:
Client side code:
function getUserset(ids,last) {
userQuery = "";
for(i=0;i<ids.length;i++)
{
userQuery += ids[i] + ",";
}
userQuery = userQuery.slice(0,-1);
return $.ajax({
type: "GET",
url: "/userset?users=["+userQuery+"]",
async: false
}).responseJSON;
}
Server code:
app.get('/userset', function (req, res) {
var accJSN = JSON.parse(fs.readFileSync(path.join(__dirname,'/public/data/users.json')));
accJSN = accJSN.users;
var users = JSON.parse(req.query.users);
var resJSN = new Array;
for(var i=0;i<users.length;i++)
{
var temp = {};
temp["id"] = users[i];
temp["fName"] = accJSN[users[i]].fName;
temp["lName"] = accJSN[users[i]].lName;
temp["profilePic"] = accJSN[users[i]].profilePic;
resJSN.push(temp);
}
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(resJSN));
})
The data I need is actually available in the response text but I cannot for the life of me figure out why the second example doesn't also include the responseJSON attribute, or, if I'm totally wrong, why the first one does. Any thoughts or solutions appreciated, thanks!
Instead of manually setting the application/json header and sending a response just use
res.json(resJSN);
instead of
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(resJSN));

Retrieve first portion from the path name [/sample/v1]

I am creating a get request in node js. I want the base url path as http://localhost:80/sample and different requests as /v1, /v2.
So, the concatenated url will be http://localhost:80/sample/v1?querystring=10.
How can I segeregate the base path as http://localhost:80/sample, since when I try to get the pathname, I am getting /sample/v1?
Please help me with node js not using express.
UPDATE:
function onRequest(request, response) {
var pathName = url.parse(request.url).pathname;
}
where the request.url is localhost:80/sample/v1?q=10.
I need to validate if its either "v1" or "v2" by fethcing in the url instead of validating with the entire pathname like pathname.indexOf('v1') process something.
So, I don't know why do you prefer scheme /{method}/{api_version}, because companies are prefer reversed to your order. (E.g. twitter console).
Example #1, if your method doesn't contain additional slashes:
function onRequest(request, response) {
var pathName = url.parse(request.url).pathname.split('/');
var version = pathName[2]; // v1 or v2
var methodName = pathName[1]; // sample
}
Example #2, if you method will contain additional /, e.g. /user/19292/v1:
function onRequest(request, response) {
var pathName = url.parse(request.url).pathname;
var match = pathName.match(/\/v\d+$/);
if(match != null) {
var version = match[0]; //v1 or v2
var methodName = pathName.replace(/\/v\d+$/, ''); // /user/19229
} else {
// No version was provided
}
}

nodejs : get url in OutgoingMessage

My goal is to intercept every outgoing message from my server in a meteor project and add some stuff (meta datas and additional contents)
I have this simple code :
var http = Npm.require( 'http' ),
originalWrite = http.OutgoingMessage.prototype.write;
http.OutgoingMessage.prototype.write = function ( chunk, encoding ) {
console.log( this, arguments );
chunk = chunk.replace( 'some code', 'elements to add' );
originalWrite.call( this, chunk, encoding );
}
It works but I cannot find the url of the current call. This is a problem because I need to add different elements according to the called url.
(nota : I have a condition to make sure the request is an html file)
The full URL isn't directly available but host and path are through the request header Host and a property path on the OutgoingMessage object.
To obtain the full URL:
var url = this.getHeader('host') + this.path; //or this._headers.host;
--
var originalWrite = http.OutgoingMessage.prototype.write;
http.OutgoingMessage.prototype.write = function () {
var url = this.getHeader('host') + this.path;
//...
return originalWrite.apply(this, arguments);
};
The reason path isn't available in the header is because the request path is part of the Request-Line. The OutgoingMessage implementation first establishes a TCP connection to the host and then issues a request on the path.
GET /path HTTP/1.1
Host: hostname

In Node.js, given a URL, how do I check whether its a jpg/png/gif?

My current method is this:
var request = require('request');
var mime = require('mime');
var fs = require('fs');
var uri = 'http://www.sweetslyrics.com/images/img_gal/25646_christina-perri-213968.jpg';
request({
'method':'GET',
'uri': uri
},function(err, response,body){
var tmp_path = '/tmp/123456';
fs.writeFile(tmp_path, body, function(err) {
console.log(mime.lookup(tmp_path)); //application/octet-stream ?????
});
});
The image is obviously a picture, but node-mime says it's application/octet-stream. Why?
Note:
- I do not want to rely on the Response Headers content-type, because based on my experience, sometimes those response headers are set incorrectly...and they do not determine the true file type. (that's why I save it to a file, and then have node-mime determine it for me!)
I want to know the best way to determine if a file is an image, with 0 margin of error.
Edit: I just realized that node-mime isn't "magic". It just checks for the extension :( ...
Edit2: I found this: https://github.com/SaltwaterC/mime-magic
Just read the first bytes of the stream, and check it for the so called "magic number".
Magic numbers are the first bits of a file which uniquely identify the
type of file.
For example:
-Every JPEG file begins with ff d8 (hex).
-Every png file begins with a 89 50 4e 47.
-There is a comprehensive table of magic numbers here
This way even if you have a file without extension you can still detect its type.
Hope this helps.
This code shows a working solution for the magic numbers approach (summary of the existing answers and information on https://github.com/request/request).
var request = require('request');
var url = "http://www.somedomain.com/somepicture.jpg";
var magic = {
jpg: 'ffd8ffe0',
png: '89504e47',
gif: '47494638'
};
var options = {
method: 'GET',
url: url,
encoding: null // keeps the body as buffer
};
request(options, function (err, response, body) {
if(!err && response.statusCode == 200){
var magigNumberInBody = body.toString('hex',0,4);
if (magigNumberInBody == magic.jpg ||
magigNumberInBody == magic.png ||
magigNumberInBody == magic.gif) {
// do something
}
}
});
There are two modules that can help you achieve this:
https://github.com/SaltwaterC/mime-magic
https://github.com/bentomas/node-mime
In the intervening time since this question was first asked, mime-magic has become unsupported and its author recommends the use of mmmagic. I don't know what happened to node-mime, the link above is a 404. I found the following article which discusses the topic as well: https://nodejsmodules.org/tags/mime
i developped this code and i test it and it work for me you can use it
var express = require('express')
var app = express()
var http = require('http').Server(app).listen(80)
var upload = require('express-fileupload')
app.use(upload())
app.get("/",(req,res)=>{
res.sendFile(__dirname+"/file.html")
})
app.post('/',(req,res)=>{
var options = {
method: 'GET',
url: req.files.filename,
encoding: null
}
if (req.files) {
if (req.files.filename.data.toString('hex',0,4) == '89504e47' || req.files.filename.data.toString('hex',0,4) == 'ffd8ffe0' || req.files.filename.data.toString('hex',0,4) == '47494638' ) {
var file = req.files.filename
filename = file.name
file.mv('./upload/'+filename,(err)=>{
if (err) {
console.log('small err')
} else {
res.send('DONE')
}
})
} else {
console.log('it not an image')
}
}
})

Categories

Resources