Pass value from http.request or superagent to http.createServer NodeJs - node.js

I am not sure what the issue is but I think I have to make this async or promise based (idk how). I simply want to pass the callback to http server on res.end.
Can some one help please?
HTTP Request or SuperAgent passes the value to the function below. How to send this to http.createserver ?
function receiveCallback(link) {
console.log(link);
//this works fine, echos the LINK we want to 302 to
}
How to pass link to http server?
http.createServer(function (req, res) {
res.writeHead(302, {'Location': link});
res.end();
}).listen('8080');
Ex. User opens domain.com/test?somevar
somevar is sent to superagent which then produces a link
How to 302 the user to the link

If your superagent is making its own request every time the server gets a request, it would look something like this:
const http = require('http');
const url = require('url');
const request = require('superagent');
http.createServer((req, res) => {
const queryParams = url.parse(req.url, true).query;
request
.get('/get/my/link')
.send({ somevar: queryParams.somevar })
.end((err, response) => {
if (err)
throw err;
const link = response.body.link;
res.writeHead(302, { 'Location': link });
res.end();
});
}).listen('8080');

Related

response is empty when trying send a request GET with vanilla JS to express

I want to create a request GET that returns a json data type with ajax
The route is so simply like this:
app.get('/', function(req, res) {
res.json({ answer: 42})
});
When I open / in the browser it render this:
All ok, but I trying to get answer json with XMLHttpRequest vanilla JS (no jquery):
var xhr = new XMLHttpRequest();
xhr.open("GET", 'http://localhost:3000/');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'json'
xhr.addEventListener('load', function () {
alert(this.response) // response is 'null'
})
xhr.send();
the response property is null and thw browser look like this:
I get nothing back. What am I missing here?
I don't see any issue with the code It must be a cross domain issue. The reason it works from postman is it handle the preflight automatically. You need to enable cors in your express server like this.
const express = require('express')
const app = express();
var cors = require('cors')
app.use(cors())
app.get('/', function(req, res) {
res.json({ answer: 42})
});
app.listen(3000, () => {
console.log("listening");
});
Hope it helps.

Chaining a Get request from a Post request then sending to client, using Express and Google oauth

I am servicing a Post request, where I retrieve user token id in this request, I further verify the token using OAuth2Client library. When verified, I want to issue a Get request to get user info. I am not sure of the way I am chaining requests.
Code is like:
var userid;
app.post( '/oauth/google/redirect', (req, res) => {
const token = req.body.idtoken;
verify().catch(console.error);
req.get(`https://oauth2.googleapis.com/tokeninfo?id_token=${token}`, (req, res) => {
var body = "";
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
res.send(body)
});
})
});
const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client(google.clientID);
async function verify() {
const ticket = await client.verifyIdToken({
idToken: token,
audience: google.clientID, // Specify the CLIENT_ID of the app that accesses the backend
// Or, if multiple clients access the backend:
//[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
});
const payload = ticket.getPayload();
userid = payload['sub'];
// If request specified a G Suite domain:
//const domain = payload['hd'];
}
On client side, browser says it failed on post request as it took too much time returning:
POST http://mywebapp.com/oauth/google/redirect 504 (Gateway Time-out)
Signed in as: <html><body><h1>504 Gateway Time-out</h1>
The server didn't respond in time.
</body></html>
For now, I used request as a library, something like:
app.post( '/oauth/google/redirect', (req, res) => {
const token = req.body.idtoken;
verify().catch(console.error);
request(`https://oauth2.googleapis.com/tokeninfo?id_token=${token}`, function (error, response, body) {
var data={
body:body
};
res.send(data);
});
});
Still accepting a native Express solution as a better answer.

How to res.send to a new URL in Node.js/Express?

Given a GET request to URL X, how should you define res.send such that it provides a response to a completely separate URL Y?
i.e.
app.get('/', function (req, res) {
res.send to a new URL external of the app ('Success')
});
Thanks and apologies in advance for ignorance on the topic!
You want to redirect the request by setting the status code and providing a location header. 302 indicates a temporary redirect, 301 is a permanent redirect.
app.get('/', function (req, res) {
res.statusCode = 302;
res.setHeader("Location", "http://www.url.com/page");
res.end();
});
You can only send response to the request source, which is the client. There is no such thing as sending response to another "external-url" (or another server).
However, you CAN make a request to another server, wait for it's response, and respond to our client.
app.get('/', (req, res) => {
var requestOptions = {
hostname: 'serverB.com', // url or ip address
port: 8080, // default to 80 if not provided
path: '/take-request',
method: 'POST' // HTTP Method
};
var externalRequest = http.request(requestOptions, (externalResponse) => {
// ServerB done responding
externalResponse.on('end', () => {
// Response to client
res.end('data was send to serverB');
});
});
// Free to send anthing to serverB
externalRequest.write(req.data);
externalRequest.end();
});

Node.js with Express: how to redirect a POST request

I want to redirect from one URL request to another 'POST' request, like this:
var app = require('express')();
app.get('/', function(req, res) {
res.redirect('/test');
});
app.post('/test', function(req, res) {
res.send('/test page');
});
app.listen(3000, function() {
console.log('listenning on port:3000');
});
However, I can't redirect to '/test' page because it is a POST request. So what should I do to make the redirection work, keeping the '/test' request POST?
You can do this:
app.post('/', function(req, res) {
res.redirect(307, '/test');
});
Which will preserve the send method.
For reference, the 307 http code spec is:
307 Temporary Redirect (since HTTP/1.1) In this occasion, the request
should be repeated with another URI, but future requests can still use
the original URI.2 In contrast to 303, the request method should not
be changed when reissuing the original request. For instance, a POST
request must be repeated using another POST request.
For more info, see: http://www.alanflavell.org.uk/www/post-redirect.html
Keep in mind the middleware architecture: Each handler may manipulate the context, and either respond - or - call next().
By this premise, the express router is basically a middleware function you may use after "correcting" the url.
(BTW, the request app is also a function, although I'm not sure if I recommend going back so early in the chain)
Here's a kind'a example:
const router = new require('express').Router()
const user = require('../model/user')
//assume user implements:
// user.byId(id) -> Promise<user>
// user.byMail(email) -> Promise<user>
const reqUser = userPromise => (req, res, next) =>
req.user
? next()
: userPromise(req)
.then(user => { req.user = user })
.then(next, next)
//assume the sever that uses this router has a
//standard (err, req, res, next) handler in the end of the chain...
const byId = reqUser( req => user.byId(req.params.id) )
const byMail = reqUser( req => user.byMail(req.params.mail) )
router.post('/by-id/:id/friends',
byId,
(req, res) => res.render('user-friends', req.user)
)
router.post('/by-email/:email/friends',
byMail,
(req, res, next) => {
req.url = `/by-id/${req.user.id}/friends`
next()
},
router
)
The only difference between 307 and 302 is that 307 guarantees that the method and the body will not be changed when the redirected request is made.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307
I believe the question is that the node server is receiving a POST request but needs to redirect it to a different server as GET request. I recently had to deal with something similar. Here is how I solved it:
var proxy = require('express-http-proxy');
app.use('incomin/url', proxy('forwarding:server', {
//The proxyRqDecorator allows us to change a few things including the request type.
proxyReqOptDecorator: (proxyReqOpts, srcReq) => {
proxyReqOpts.method = 'GET';
return proxyReqOpts;
},
//The proxyReqPathResolver takes the Given URL and updates it to the forward path
proxyReqPathResolver: function (req) {
return new Promise( (resolve, reject) => {
setTimeout( () =>{
var value = req.body.key;
var resolvedPathValue = 'forwarding/url' + value;
console.log(`Inside forward path. The resolved path is ${resolvedPathValue}`);
resolve(resolvedPathValue);
}, 200);
});
}
}));
Keep in mind that the above proxyReqPathResolver is setup async. The synchronous vesrion and more info on express-http-proxy are described here:
https://www.npmjs.com/package/express-http-proxy

How to forward a request to other endpoint in node.js

In my scenario I need forward get request to another end point. In my machine there are two servers php and node.js server. Node.js is like a "man in the middle", PHP server must work in the same way.
Node.js server code
var express = require('express');
var fs = require('fs');
var path = require('path');
var http = require('http');
var https = require('https');
var app = express();
var HTTP_PORT = 3000;
// Create an HTTP service
http.createServer(app).listen(HTTP_PORT,function() {
console.log('Listening HTTP on port ' + HTTP_PORT);
});
//endpoint for tracking
app.get('/track', function(req, res) {
sendRequestToOtherEndPoint(req);
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
});
function processRequest(req){
console.log("request processed");
}
function sendRequestToOtherEndPoint(req){
//magic here :)
}
When this server receive a get request in port 3000, it process request information and it must forward the same requesto to another end point.
For example:
Get localhost:3000/track?param1=1&param2=2
Server process get request
Server forward get request to localhost/final-endpoint?param1=1&param2=2
Depending on what you're trying to do, you can create a new request to the end-point:
//endpoint for tracking
app.get('/track', function(req, res) {
req.get({url: 'http://end-point', headers: req.headers});
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
});
More info: https://github.com/request/request
There are a couple of useful libraries that one could use:
http-proxy-middleware:
const proxy = require('http-proxy-middleware')
var apiProxy = proxy('/track', {target: 'http://end-point'});
app.use(apiProxy)
axios-express-proxy
import express from 'express';
import { Proxy } from 'axios-express-proxy';
const app = express();
const port = 3000;
app.get('/track', (req, res) => Proxy('http://end-point', req, res));
In you case res.redirect might help.
app.get('/track', function(req, res) {
// process the request
// then redirect
res.redirect('/final-endpoint');
});
Then catch the redirected request in final endpont.
app.get('/final-endpoint', function(req, res) {
// proceess redirected request here.
});
See the Express docs
If your second endpoint is on a different server, (e.g. PHP) then you're going to need to either redirect the client (as in sohel's answer), or spoof a request from Node to the PHP server and then send the response back to the client. This latter option is definitely non-trivial so I would question whether it's crucial not to use a client redirect.
If you're talking about two express endpoints, then I think the simplest answer might be not to actually forward at all, but just use the endpoint callback directly instead:
app.get('/track', trackCallback);
app.get('/otherendpoint', otherendpointCallback);
function otherendpointCallback(req, res) {
// do your thing
}
function trackCallback(req, res) {
otherendpointCallback(req, res);
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
};
Depending on exactly what you want to do at the other end point, you might need to spoof some of req's fields (e.g. req.url)

Resources