How to add proxy to Node / Express site? - json

My site is running on Node and using the Express framework.
My goal is to gather data from the Yahoo Placefinder api. It does not support JSONP, so I need to send my JQuery.getJSON request to my own proxy. My proxy would then send an http request to the Placefinder api, and echo the response.
If I were using php instead of Node, I would just make a new php file that includes a curl request to the placefinder api and echo the response.
But, I am using Node and I'm not sure where to start.
And, I'm using the Express framework.
My Questions are:
Where would the proxy fit within the Express framework? The public folder?
Where can I find some info on how to code a proxy in Node?
Will I need to modify the configuration of my Rackspace cloud (ubuntu) server in order for this to be possible?

See node-http-proxy. It should be better than implementing your own proxy.
Express lets you add middlewares as arguments when you do express.createServer(). Or, you can add them afterwards by using .use(proxy).
I don't think so.
To give an example (untested code):
var httpProxy = require('http-proxy'), express = require('express');
var yahooProxy = httpProxy.createServer(80, 'yahoo.com');
var app = express.createServer();
app.configure(function () {
app.use('/yahoo', yahooProxy);
});
...

Here's another example with 1.0.X that demonstrates header injection.
var express = require( 'express' );
var proxy = require( 'http-proxy' ).createProxyServer;
var app = express();
app.configure(function() {
// Inject some request headers here before we proxy...
app.use( function( req, res, next ) {
req.headers[ 'x-my-header' ] = 'blah blah';
next();
});
// Proxy based on path...
app.use( '/stack', proxy({ target: 'http://stackoverflow.com'} ).web );
app.use( '/yahoo', proxy({ target: 'http://yahoo.com'} ).web );
app.use( function( req, res ) {
res.send({ ok: false, message: 'Not much here.' })
});
}).listen( 3000 );

You can just add another route to your express app, perhaps at /api/yahoo/....
This view function will then make a call to the Yahoo API, probably using: http://nodejs.org/docs/v0.4.9/api/http.html#http.request, and then when that request finishes you simple return the result as JSON.
However, keep in mind that your proxy is public and that anyone can make requests through it. I would suggest some basic authorization. A generated value which you provide to the page making the request should work.

Using http-proxy 1.0 with express:
var httpProxy = require('http-proxy');
var apiProxy = httProxy.createProxyServer();
app.get("/api/*", function(req, res){
apiProxy.web(req, res, { target: 'http://google.com:80' });
});

Nowadays this seems to be the easiest solution to add a proxy to Express:
https://www.npmjs.org/package/proxy-middleware

Related

google actions sdk: using third party server to build templated responses

My Google Actions project points to a Google Cloud Function as a webhook. In the google cloud function I am able to create the conversation responses using conv.ask(...).
However, what I am trying to do is: build a generic conversation content framework that resides on another server (also google cloud function) where I would like to compose the response and send it back to the webhook function.
The relevant code in both these servers are like this:
// in the webhook function
app.intent('actions.intent.MAIN', (conv, input) => {
// here I would like to call the second google function by
// passing, say, the input and receiving a response that can
// be passed on to the conv
// something like
// assume request-promise is being used
//
var options = {
method: 'POST',
uri: '..',
body: {...},
json: true
};
rp(options)
.then(resp => {
conv.ask(resp) // this is what I would like to do
});
});
In the second Google Functions server, I am using express as middleware. Here on some logic templated responses get built
const ..
const {
SimpleResponse,
BasicCard,
...
} = require('actions-on-google');
...
const express = require('express');
var app = express();
...
app.post('/main', function(req, res, next) {
// here I would like to compose the response
// and send it to the earlier function
var convresp = new SimpleResponse({...});
..
res.send(convresp);
// this seems to be only sending the json
// and causes the receiving response to give an error
// when applying to conv.ask in the above code
});
Question is: how should the response be sent from the second function so that it can be "pasted" to the conv.ask functionality in the first function?. Thanks

Proxy webpack-dev-server based on request payload to return json file

So I've searched and I think a saw the entire internet but no solution regarding the issue I encounter.
I have multiple http request which I want to mock. All request have the same url but deviate based on the requestPayload which contain a graphQl query. Based on this query I want to return a specific json file. All proxy settings I have found can handle parameters but do not handle responses based on requestPayload.
Have you taken a look over this functionality?
https://webpack.js.org/configuration/dev-server/#devserver-before
as far as webpack-dev-server is an instance of express app you are able to setup it in the before/after hooks. Hooks get app (server) instance as a first argument.
so for your case your webpack development config would look like:
module.exports = {
//...
devServer: {
before: function(app) {
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.get('/some/path/graphql', function(req, res) {
var query = req.body;
// ...your custom logic of
// specific query handling goes here
if (condition(query)) {
res.json({ mockedResponse: 'foo' });
} else {
res.json({ mockedResponse: 'bar' });
}
});
}
}
};
UPD: keep in mind if you're using proxy config for devServer you might want to use after hook instead of before to let your requests be proxified if needed.

Handling multipart/formdata and json payloads with Express?

I have an express server that handles json payloads (using body-parser). It's a pretty standard setup:
const app = express();
...
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
...
app.post('/api/v1/login', usersController.login);
...etc
But now I have one query - a hook from an outside service - that's submitting data to me as multipart/formdata. How do I deal with those? Do I have to rejigger my entire setup?
Thanks.
I use connect-multiparty package.
An option could be like this (more specific):
var multipart = require('connect-multiparty');
app.post('/api/v1/login', multipart(), function(req, resp) {
console.log(req.files); // in req.files are the files
});
Or just:
var multipart = require('connect-multiparty');
app.use(multipart());

Sending nested object via post request

I'm running this little node express server, which is supposed to check if the voucher is valid later and then send an answer back to the client
this is my code
app.post('/voucher', function (request, response) {
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
response.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
if ( request.method === 'OPTIONS' ) {
response.writeHead(200);
response.end();
return;
}
console.log(request)
let results;
let body = [];
request.on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
results = Buffer.concat(body).toString();
// results = JSON.parse(results);
console.log('#### CHECKING VOUCHER ####', results)
let success = {success: true, voucher: {name: results,
xxx: 10}}
success = qs.escape(JSON.stringify(success))
response.end(success)
} )
}
);
It is obviously just an example and the actual check is not implemented yet. So far so good.
Now on the client side where I work with REACT, I can not seem to decode the string I just send there.
there I'm doing this
var voucherchecker = $.post('http://localhost:8080/voucher', code , function(res) {
console.log(res)
let x = JSON.parse(res)
console.log(x)
console.log(qs.unescape(x))
It gives me the error
Uncaught SyntaxError: Unexpected token % in JSON at position 0
When I do it the other way arround
let x = qs.unescape(res)
console.log(x)
console.log(JSON.parse(x))
Than it tells me
Uncaught TypeError: _querystring2.default.unescape is not a function
Maybe you can help me? I don't know what the issue is here. Thank you.
Also another question on this behalf, since I'm only a beginner. Is there smarter ways to do such things than I'm doing it now? I have react which renders on the client and I have a mini express server which interacts a few times with it during the payment process.
The both run on different ports.
What would be the standard way or best practice to do such things?
I'm a bit perplexed as to why your backend code has so much going on in the request.
Since you asked for if there is a different way to write this, I will share with you how I would write it.
Server
It seems that you want your requests to enable CORS, it also seems that you originally wanted to parse a JSON in your request body.
This is how I would recommend you re-write your endpoint
POST /voucher to take a request with body JSON
{
code: "xxxxx"
}
and respond with
{
success: true,
voucher: {
name: results,
xxx: 10
}
}
I would recommend you use express's middleware feature as you will probably use CORS and parse JSON in most your requests so in your project I would.
npm install body-parser
npm install cors
then in your app initialization
var bodyParser = require('body-parser')
var cors = require('cors')
var app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json you can choose to just pars raw text as well
app.use(bodyParser.json())
// this will set Access-Control-Allow-Origin * similar for all response headers
app.use(cors())
You can read more about body-parser and cors in their respective repos, if you don't want to use them I would still recommend you use your own middleware in order to reduse future redundancy in your code.
So far this will substitute this part of your code
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
response.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
if ( request.method === 'OPTIONS' ) {
response.writeHead(200);
response.end();
return;
}
console.log(request)
let results;
let body = [];
request.on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
results = Buffer.concat(body).toString();
// results = JSON.parse(results);
Now your route definition can just be
app.post('/voucher', function (request, response) {
var result = request.body.code // added by body-parser
console.log('#### CHECKING VOUCHER ####', result)
// express 4+ is smart enough to send this as json
response.status(200).send({
success: true,
voucher: {
name: results,
xxx: 10
}
})
})
Client
your client side can then be, assuming $ is jquery's post function
var body = {
code: code
}
$.post('http://localhost:8080/voucher', body).then(function(res) {
console.log(res)
console.log(res.data)
return res.data
})

How can I access my couchdb from my node server using REST/JSON/GET/POST?

I'm trying to access my couchdb from a node.js server.
I've followed the nodejs tutorial, and have set up this simple nodejs server:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(80, "127.0.0.1");
console.log('Server running at http://127.0.0.1:80/');
I would like to make RESTful http and POST requests to the nodejs server. The nodejs server should then be able to make GET/POST request to the Couchdb, which responds with JSON objects.
How might I do this?
First of all I am the author of nano and will use it in this response.
Here go some simple instructions to get started with node.js and CouchDb.
mkdir test && cd test
npm install nano
npm install express
If you have couchdb installed, great. If you don't you will either need to install it setup a instance online at iriscouch.com
Now create a new file called index.js. Inside place the following code:
var express = require('express')
, nano = require('nano')('http://localhost:5984')
, app = module.exports = express.createServer()
, db_name = "my_couch"
, db = nano.use(db_name);
app.get("/", function(request,response) {
nano.db.create(db_name, function (error, body, headers) {
if(error) { return response.send(error.message, error['status-code']); }
db.insert({foo: true}, "foo", function (error2, body2, headers2) {
if(error2) { return response.send(error2.message, error2['status-code']); }
response.send("Insert ok!", 200);
});
});
});
app.listen(3333);
console.log("server is running. check expressjs.org for more cool tricks");
If you setup a username and password for your CouchDB you need to include it in the url. In the following line I added admin:admin# to the url to exemplify
, nano = require('nano')('http://admin:admin#localhost:5984')
The problem with this script is that it tries to create a database every time you do a request. This will fail as soon as you create it for the first time. Ideally you want to remove the create database from the script so it runs forever:
var express = require('express')
, db = require('nano')('http://localhost:5984/my_couch')
, app = module.exports = express.createServer()
;
app.get("/", function(request,response) {
db.get("foo", function (error, body, headers) {
if(error) { return response.send(error.message, error['status-code']); }
response.send(body, 200);
});
});
});
app.listen(3333);
console.log("server is running. check expressjs.org for more cool tricks");
You can now either manually create, or even do it programmatically. If you are curious on how you would achieve this you can read this article I wrote a while back Nano - Minimalistic CouchDB for node.js.
For more info refer to expressjs and nano. Hope this helps!
I have a module (node-couchdb-api) I've written for this exact purpose. It has no ORM or other features like that, it's just a simple wrapper for the HTTP API that CouchDB offers. It even follows the conventions established by Node.JS for async callbacks, making your code that much more consistent all-around. :)
You can use node.js module such as Cradle to work with CouchDB.
Here is a list of available Node.JS modules: https://github.com/joyent/node/wiki/modules
Just make HTTP requests. I would recommend request
Here's an example from my code
request({
"uri": this._base_url + "/" + user._id,
"json": user,
"method": "PUT"
}, this._error(cb));
Here's another example from my code
// save document
"save": function _save(post, cb) {
// doc changed so empty it from cache
delete this._cache[post.id];
// PUT document in couch
request({
"uri": this._base_url + "/" + post._id,
"json": post,
"method": "PUT"
}, this._error(function _savePost(err, res, body) {
if (body) {
body.id = post.id;
body.title = post.title;
}
cb(err, res, body);
}));
}