I'm trying provide the response of an external API call when I perform a local GET request but struggling with how to get this to work.
My code at the moment is:
app.get('/', function(req, res){
request.post('http://data.fixer.io/api/latest?access_key=' + apikey +
'&symbols=gbp', function(err, res, body) {
console.log(body)
})
res.render('index')
})
My knowledge and experience with callbacks and async programming is limited, but how do I pass the response of the request POST into the GET request to then pass it to the index?
Thanks!
Callbacks can be difficult to understand, and the problem you describe isn't uncommon (it even has a name - Callback Hell). Partly the reason why Node introduced the async / await syntax - here's the equivalent of your code in that style
app.get('/', async (req, res, next) => {
try {
const uri = `http://data.fixer.io/api/latest?access_key=${apikey}&symbols=gbp`;
const data = await request.post(uri);
return res.render('index', { data }); // or pass whatever you need from `data` into the view
} catch (e) {
return next(e);
}
}
Notice the one big difference? No callbacks and you get all the same benefits of asynchronous code with bonus of writing code in a synchronous style.
You can chain calls in Express, so it's very easy to call an external service within a GET request, e.g.
app.get('/', function(req, res){
request.post('http://data.fixer.io/api/latest?access_key=' + apikey + '&symbols=gbp', function(err, response, body) {
console.log(body)
res.send(body);
})
})
In this case we're sending back the raw response from the POST, it is easy to wrap this in another object, e.g.
res.send( { status: 'ok', post_result: body });
Related
I would like to post at the path /users and then immediately post to /users/:id, but the actions need to be different at each of these URLs, so I can't use the array method for applying the same middleware to different URLs
The idea is that POST(/users/:id, ...) will never be called by the client. It only gets called immediately after POST(/users, ...)
When using express, you are providing a handler function for a specific endpoint. Actually it's an array of those functions (middlewares). That means that you can switch from :
route.post('/users/`, (req, res, next) => {
// do your magic
});
to
route.post('/users/', handleMyCall);
This way you can easily reuse those functions in multiple endpoints without your need to actually make requests:
route.post('/users/', (req, res) => {
// do something +
handleMyCall(req, res);
// either return the result of this call, or another result
});
route.post('/users/:userID', (req, res) => {
// do another operation +
handleMyCall(req, res);
});
Update:
Using GET or POST differs in the way the data is sent to the server. You can use both for your cases, and it really depends on the testing client you have.
Typically, a GET request is done to query the database and not do any actions. POST is usually used to create new entities in the database.
In your scenario, I'd guess you would have post('/users/) in order to create a user. And then have get('/users/:userID') to find that user and return it to the client.
You can easily have different endpoints with different handles for those cases.
As I understood from the comments, you'll need a POST request on /users (to persist data in some database) and GET /users/:id to retrieve these data, which is very different from POSTing the same thing on 2 different endpoints.
POST is generally used to persist and GET to retrieve data.
I'll assume you use some kind of NoSQL DB, perhaps MongoDB. MongoDB generate a unique ID for each document you persist in it.
So you'll have to have 2 routes :
const postUser = async (req, res, next) => {
try {
// persist your user here, perhaps with mongoose or native mongo driver
} catch (e) {
return next(e);
}
}
const getUserById = async (req, res, next) => {
try {
// get your user here thanks to the id, in req.params.id
} catch (e) {
return next(e);
}
}
export default (router) => {
router.route('/users').post(postUser);
router.route('/users/:id').get(getUserById);
};
I'm new to node.js so I'll try my best to explain the problem here. Let me know if any clerification is needed.
In my node.js application I'm trying to take a code (which was received from the response of the 1st call to an API), and use that a code to make a 2nd request(GET request) to another API service. The callback url of the 1st call is /pass. However I got an empty response from the service for this 2nd call.
My understanding is that after the call back from the 1st call, the function in app.get('/pass', function (req, res).. gets invoked and it sends a GET request. What am I doing wrong here? Many thanks in advance!
Here is the part where I try to make a GET request from node.js server and receive an empty response:
app.get('/pass', function (req, res){
var options = {
url: 'https://the url that I make GET request to',
method: 'GET',
headers: {
'authorization_code': code,
'Customer-Id':'someID',
'Customer-Secret':'somePassword'
}
};
request(options, function(err, res, body) {
console.log(res);
});
});
Im a little confused by what you are asking so ill just try to cover what i think you're looking for.
app.get('/pass', (req, res) => {
res.send("hello!"); // localhost:port/pass will return hello
})
Now, if you are trying to call a get request from the request library when the /pass endpoint is called things are still similar. First, i think you can remove the 'method' : 'GET' keys and values as they are not necessary. Now the code will be mostly the same as before except for the response.
app.get('/pass', (req, res) => {
var options = {
url: 'https://the url that I make GET request to',
headers: {
'authorization_code': code,
'Customer-Id':'someID',
'Customer-Secret':'somePassword'
}
};
request(options, function(err, res, body) {
// may need to JSONparse the body before sending depending on what is to be expected.
res.send(body); // this sends the data back
});
});
I am building a NodeJS server using Express4. I use this server as a middleman between frontend angular app and 3rd party API.
I created a certain path that my frontend app requests and I wish on that path to call the API multiple times and merge all of the responses and then send the resulting response.
I am not sure how to do this as I need to wait until each API call is finished.
Example code:
app.post('/SomePath', function(req, res) {
var merged = [];
for (var i in req.body.object) {
// APIObject.sendRequest uses superagent module to handle requests and responses
APIObject.sendRequest(req.body.object[i], function(err, result) {
merged.push(result);
});
}
// After all is done send result
res.send(merged);
});
As you can see Im calling the API within a loop depending on how many APIObject.sendRequest I received within request.
How can I send a response after all is done and the API responses are merged?
Thank you.
Check out this answer, it uses the Async module to make a few requests at the same time and then invokes a callback when they are all finished.
As per #sean's answer, I believe each would fit better than map.
It would then look something like this:
var async = require('async');
async.each(req.body.object, function(item, callback) {
APIObject.sendRequest(item, function(err, result)) {
if (err)
callback(err);
else
{
merged.push(result);
callback();
}
}
}, function(err) {
if (err)
res.sendStatus(500); //Example
else
res.send(merged);
});
First of all, you can't do an async method in a loop, that's not correct.
You can use the async module's map function.
app.post('/SomePath', function(req, res) {
async.map(req.body.object, APIObject.sendRequest, function(err, result) {
if(err) {
res.status(500).send('Something broke!');
return;
}
res.send(result);
});
});
I am currently building a small node application that makes a few api calls and renders a webpage with charts on it. I'm using express and jade as the render engine.
The problem is that I'm quite new to javascript and I don't know how to scheme out my http requests so I can pass an object of variables I got from the api (http get) when there is more than one request. I don't know how to map it out to make a single object and send it to the jade rendering engine.
Here is what I have so far :
app.get('/test', function(req, res) {
apiRequestGoesHere(name, function(error, profile) {
//Get some data here
});
anotherApiRequest(tvshow, function(error, list) {
//Get some data here
});
res.render('test', data);
});
As it is right now, the page renders and the requests are not done yet, and if I place res.render inside one of the request, I can't access the other's data.
So what I want is a way to set it up so I can have multiple api calls, then make an object out of some elements of what is returned to me from the rest api and send it to Jade so I can use the data on the page.
You probably want to use async to help with this. async.parallel is a good choice for something simple like this:
app.get('/test', function(req, res) {
async.parallel([
function(next) {
apiRequestGoesHere(name, function(error, profile) {
//Get some data here
next(null, firstData);
});
},
function(next) {
anotherApiRequest(tvshow, function(error, list) {
//Get some data here
next(null, secondData);
});
}], function(err, results) {
// results is [firstData, secondData]
res.render('test', ...);
});
});
The first argument to those functions next should be an error if relevant (I put null) - as soon as one is called with an error, the final function will be called with that same error and the rest of the callbacks will be ignored.
You can async parallel.
async.parallel([
function(callback){
// Make http requests
// Invoke callback(err, result) after http request success or failure
},
function(callback){
// Make http requests
// Invoke callback(err, result) after http request success or failure
}
],
// optional callback
function(err, results){
// the results array will be array of result from the callback
});
The reason your page renders is the callbacks haven't "called back" yet. To do what you want, you would need to do something like:
app.get('/test', function(req, res) {
apiRequestGoesHere(name, function(error, profile) {
//Get some data here
anotherApiRequest(tvshow, function(error, list) {
//Get some data here
res.render('test', data);
});
});
});
This strategy leads to what is known as "pyramid code" because your nested callback functions end up deeper and deeper.
I would also recommend the step library by Tim Caswell. It would make your code look something like:
var step = require('step');
app.get('/test', function(req, res) {
step(
function () {
apiRequestGoesHere(name, this)
},
function (error, profile) {
if error throw error;
anotherApiRequest(tvshow, this)
},
function done(error, list) {
if error throw error;
res.render('test', list)
}
)
});
You could also use the group method to make the calls in parallel and still maintain the sequence of your callbacks.
Gl,
Aaron
There are many ways to mock requests using things like supertest and nock but what I'm looking to do is to be able to create fake request objects, as if the request was going to a different URL, that can be passed on to other processing functions.
app.get("/render", function(req, res) {
// how do I do this?
var fake = createFakeRequest("/bar/?baz=qux", req);
// I want doStuff to believe the request came to /bar/?baz=qux
doStuff(fake, function(err, result) {
res.send(result);
});
});
I'm aware I could modify all of he variables such as req.path, req.query, req.url but I'm worried I may miss something, and it seems like someone out there must have already solved this problem.
The reason I need this behavior is that for any given URL in my CMS, there can be multiple drafts. Each draft will have different content elements, but those individual content elements may have logic based on the URL or query parameters. So even though the request came in as /render/?draft=1&url=/foo/bar/, I want the content element processors to believe the request came in to /foo/bar/ and be oblivious to the version system which actually handled the initial HTTP request.
Not sure to understand but seems like url rewriting, so using a middleware could work
function urlRewrite(req, res, next){
req.url ="...";
next();
}
and so
app.use(urlRewrite);
Be sure to use it at the right place (depending on your server goal)
Cause we maybe need params before the rewrite... and if rewrite, you may need it after...
EDIT
In my framework:
server.before(extractPath);
server.before(urlParams);
server.before(pathParams);
server.get("/foo", route.foo);
So I could write
server.before(extractPath);
=> server.before( function(req, res, next){
urlRewrite(req, res, function(){
extractPath(req, res, next);
}
});
server.before(urlParams);
server.before(pathParams);
server.get("/foo", route.foo);
If urlRewrite depends on urlParams, I could write
server.before(extractPath);
server.before(urlParams);
=> server.before( function(req, res, next){
urlRewrite(req, res, function(){
extractPath(req, res, function(){
urlParams(req, res, next);
});
});
});
server.before(pathParams);
server.get("/foo", route.foo);
As I said, it depends on your framework