Simple bluebird example with restify doesn't work - promise

taking straight from this post:
This code never executes.
var Promise = require("bluebird");
Promise.promisifyAll(require("restify"));
var restify = require("restify");
var http = require('http');
const PORT=7070;
function handleRequest(request, response){
response.end('It Works!! Path Hit: ' + request.url);
}
var server = http.createServer(handleRequest);
server.listen(PORT, function(){
console.log("Server listening on: http://localhost:%s", PORT);
});
var client = restify.createJsonClientAsync({
url: 'http://127.0.0.1:7070'
});
client.get("/foo").spread(function(req, res, obj) {
console.log(obj);
});
I only put together this simple example to prove it to myself after my production code didn't work. I can hit localhost:7070 with curl and I get the expected results.
In a nutshell: I need to execute 3 GET calls to a server before I can create a POST and hence my need for promises.
Anyone can shed some insight? I can't imagine this being simpler.

UPDATE
Apparently i did not read the question correctly, here is a working example of 2 gets using a promisified restify json client. you would just do another spread in the body of the second spread for your post.
var promise = require('bluebird');
var restify = require('restify');
promise.promisifyAll(restify.JsonClient.prototype);
var client = restify.createJsonClient({
url: 'http://localhost:8080',
version: '*'
});
client.getAsync('/api/resource/1').spread(function(req, res, obj) {
console.log('result 1', obj);
return client.getAsync('/api/resource/2').spread(function(req, res, obj) {
console.log('result 2', obj);
});
});
As I stated in my comments, I would not promisify restify itself. Instead I would use either a handler whose body executes promise code or a chain of handlers (which can also have promises in the body). restify should only receive the request and execute the handler.
I will use modified versions of the basic example from the restify page to illustrate each.
Promise in the message body using knex.js which returns a promise
var knex = require('knex')(connectionConfig);
var restify = require('restify');
function promisePost(req, res, next) {
// get 1
knex.select('*')
.from('table1')
.where('id', '=', req.body.table1_id)
.then(function(result1) {
// get 2
return knex.select('*')
.from('table2')
.where('id', '=', req.body.table2_id)
.then(function(result2) {
return knex('table3').insert({
table1_value: result1.value,
table2_value: result2.value
})
.then(function(result3) {
res.send(result3);
return next();
});
});
});
}
var server = restify.createServer();
server.use(restify.bodyParser());
server.post('/myroute', promisePost);
server.listen(8080, function() {
console.log('%s listening at %s', server.name, server.url);
});
now with chained handlers
var knex = require('knex')(connectionConfig);
var restify = require('restify');
function get1(req, res, next) {
knex.select('*').from('table1')
.where('id', '=', req.body.table1_id)
.then(function(result1) {
res.locals.result1 = result1;
return next();
});
}
function get2(req, res, next) {
knex.select('*').from('table2')
.where('id', '=', req.body.table2_id)
.then(function(result2) {
res.locals.result2 = result2;
return next();
});
}
function post(req, res, next) {
knex('table3').insert({
table1_value: res.locals.result1,
table2_value: res.locals.result2
})
.then(function(result3) {
res.send(result3);
return next();
});
}
var server = restify.createServer();
server.use(restify.bodyParser());
server.post('/myroute', get1, get2, post);
server.listen(8080, function() {
console.log('%s listening at %s', server.name, server.url);
});

Related

`next.js` api is resolved before promise fullfill?

I want to achieve something like this:
call my website url https://mywebsite/api/something
then my next.js website api will call external api
get external api data
update external api data to mongodb database one by one
then return respose it's status.
Below code is working correctly correctly. data is updating on mongodb but when I request to my api url it respond me very quickly then it updates data in database.
But I want to first update data in database and then respond me
No matter how much time its take.
Below is my code
export default async function handler(req, res) {
async function updateServer(){
return new Promise(async function(resolve, reject){
const statusArray = [];
const apiUrl = `https://example.com/api`;
const response = await fetch(apiUrl, {headers: { "Content-Type": "application/json" }});
const newsResults = await response.json();
const articles = await newsResults["articles"];
for (let i = 0; i < articles.length; i++) {
const article = articles[i];
try {
insertionData["title"] = article["title"];
insertionData["description"] = article["description"];
MongoClient.connect(mongoUri, async function (error, db) {
if (error) throw error;
const articlesCollection = db.db("database").collection("collectionname");
const customQuery = { url: article["url"] };
const customUpdate = { $set: insertionData };
const customOptions = { upsert: true };
const status = await articlesCollection.updateOne(customQuery,customUpdate,customOptions);
statusArray.push(status);
db.close();
});
} catch (error) {console.log(error);}
}
if(statusArray){
console.log("success", statusArray.length);
resolve(statusArray);
} else {
console.log("error");
reject("reject because no statusArray");
}
});
}
updateServer().then(
function(statusArray){
return res.status(200).json({ "response": "success","statusArray":statusArray }).end();
}
).catch(
function(error){
return res.status(500).json({ "response": "error", }).end();
}
);
}
How to achieve that?
Any suggestions are always welcome!

How to use superagent when testing in Jest-CLI?

I need to fetch some real data in my tests from a remote url. I Superagent is not being mocked. I have done that by including node_modules/superagent/ in unmockedModulePathPatterns.
This is the file I am trying to test, the .end() function is never called.
This is my test, which fails with a timeout error.
jest.dontMock("../Stocks.js");
jest.dontMock("superagent");
describe("Stock Actions", () => {
var makeRequest = require('../Stocks')
pit("doesn't crash", function () {
var promise = makeRequest("Hello World")
promise.then(function (str) {
expect(str).toBe("yay");
});
return promise;
});
});
And this is the module it's trying to test:
import Reflux from 'reflux';
import request from 'superagent';
console.log("request-superagent", request)
const makeRequest = Reflux.createAction({ asyncResult: true });
const Store = Reflux.createStore({
init() {
this.listenTo(makeRequest, 'onMakeRequest');
},
onMakeRequest(url) {
request('GET', 'http://api.example.com/list/')
.end(function (err, res) {
console.log("res.text", res.text);
if (!res.ok) {
makeRequest.failed("aw");
}
makeRequest.completed("yay");
});
}
});
module.exports = makeRequest;
How do I use superagent in jest-cli?

request hangs on sails error

If you make a request to sails via supertest, the response hangs if you return an error.
Here, we have already lifted sails, and will run this as an integration test against a live db.
var sails = require('sails').lift();
var request = require('supertest');
var app = sails.hooks.http.app;
describe('The creation of a model',function(){
it('should not create a duplicate',function(done){
var user = request.agent(app);
user
.post('/api/create')
.end(function(err,res){
//never gets here, your test will hang
done();
});
});
});
//controller.js
module.exports = {
// /api/create routes here
create:function(req,res){
var params = {
name:"invalid"
};
SomeAction(params,function(err,results){
if (err) {
//the problem is here.
return err;
}
res.json(results);
});
}
};
If you make a supertest request to sails and the function just returns a value, ie. you don't use res.send() or res.json() it will hang the request for supertest. Here's the right way to do it:
var sails = require('sails').lift();
var request = require('supertest');
var app = sails.hooks.http.app;
describe('The creation of a model',function(){
it('should not create a duplicate',function(done){
var user = request.agent(app);
user
.post('/api/create')
.end(function(err,res){
//never gets here, your test will hang
done();
});
});
});
//controller.js
module.exports = {
// /api/create routes here
create:function(req,res){
var params = {
name:"invalid"
};
SomeAction(params,function(err,results){
if (err) {
//you need to send a response to the
res.json({
error:"an error occured"
});
}
res.json(results);
});
}
};

Why isn't the server sending or the client receiving data via socket.io in my express app?

My node app posts an object (consisting of data collected in a form on the client) to Salesforce via their API. On receiving a success or error message, I would like to send it to the client-side, then display it. Socket.io seemed like the tool for this in my simple node/express3 app, but beyond the simple demo I'm not able to get data to pass between my server and my client.
My relevant server side code:
var express = require('express');
var port = 5432;
var app = module.exports = express();
var server = require('http').createServer(app);
var nforce = require('nforce');
var org = nforce.createConnection({
clientId: 'MY_CLIENT_ID',
clientSecret: 'MY_CLIENT_SECRET',
redirectUri: 'http://localhost:5432/oauth/_callback'
});
var io = require('socket.io').listen(server);
// here I authenticate with Salesforce, this works fine
app.post('/salesforce', function(req, res){
var lead = nforce.createSObject('Lead');
// here I construct the lead object, which also works fine
org.insert(lead, oauth, function(err, res) {
if (err === null) {
console.log(res);
leadSuccessMessage(res);
}
else {
console.log(err);
var error = {
errorCode: err.errorCode,
statusCode: err.statusCode,
messageBody: err.messageBody
};
console.log(error);
leadErrorMessage(error);
}
});
}
function leadSuccessMessage(res) {
var resp = res;
console.log('called success message from server');
io.sockets.on('connection', function (socket) {
socket.emit('sfRes', resp);
socket.on('thanks', function (data) {
console.log(data);
});
});
}
function leadErrorMessage(error) {
var err = error;
console.log('called error message from server');
io.sockets.on('connection', function (socket) {
console.log("socket is: " + socket);
socket.emit('sfRes', err);
socket.on('thanks', function (data) {
console.log(data);
});
});
}
And my relevant client side scripts:
<script src="/socket.io/socket.io.js"></script>
<script>
current.page = document.URL;
console.log("current page is: " + current.page);
var socket = io.connect(current.page);
socket.on('sfRes', function (data) {
console.log("client received: " + data);
fst.showLeadStatus(data);
socket.emit('thanks', {message: "received server feedback"});
});
</script>
When I post the form containing valid data using a spicy little AJAX call:
postToSF: function(){
$('#submitLead').on('click', function(e){
e.preventDefault();
var formData = $('#lead_form').serialize();
$.ajax({
type: 'POST',
url: '/salesforce',
data: formData,
success: function(){
fst.log('success!');
},
error: function(xhr, ajaxOptions, thrownError){
console.error(xhr.status); // 0
console.error(thrownError);
}
});
});
}
All I get are tears, and these in the server-side console:
// the result of `console.log(res)`
{ id: '00Qa000001FZfhKEAT', success: true, errors: [] }
// and proof that `leadSuccessMessage()` got called
called success message from server
Instead of calling this function from a client-side object as it's supposed to:
showLeadStatus: function(response){
if (response.success) {
fst.log("showing lead status as: " + response);
$('#leadStatus').addClass('success').removeClass('error').fadeIn().delay(4000).fadeOut();
}
else {
fst.log("showing lead status as: " + response);
$('#leadStatus').text(response.messageBody).addClass('error').removeClass('success').fadeIn().delay('4000').fadeOut();
}
$('#startOver').click();
}
Which works fine if I call it in the console passing it the data the server is supposed to be socketing over:
// this works, gosh darn it
fst.showLeadStatus({ id: '00Qa000001FZfhKEAT', success: true, errors: [] });
The Salesforce post error case doesn't surface anything to the client either. And there are no errors in the client or server console to contend with.
I'm stumped. Please help!
I would do something like this -
var mysocket = null;
var io = require('socket.io').listen(server);
io.sockets.on('connection', function (socket) {
mysocket = socket;
socket.on('thanks', function (data) {
console.log(data);
});
});
app.post('/salesforce', function(req, res){
....
....
})
function leadSuccessMessage(res) {
var resp = res;
console.log('called success message from server');
if(mysocket)
mysocket.emit('sfRes', resp);
}
function leadErrorMessage(error) {
var err = error;
console.log('called error message from server');
if(mysocket)
mysocket.emit('sfRes', err);
}

How to make middleware for response on all ajax requests

I need to make a single middleware that will handle each response to web user. I try to make something like the following:
function ajaxResponseMiddleware(req, res, next) {
var code = res.locals._code || 200;
var data = res.locals._response;
res.json(code, data);
}
app.get('/ajax1', function(req, res, next){
// Do something and add data to be responsed
res.locals._response = {test: "data2"};
// Go to the next middleware
next();
}, ajaxResponseMiddleware);
app.get('/ajax2', function(req, res, next){
// Do something and add data to be responsed
res.locals._response = {test: "data2"};
res.locals._code = 200;
// Go to the next middleware
next();
}, ajaxResponseMiddleware);
The response is handled in ajaxResponseMiddleware function where I can add some default state for all my ajax responses.
One thing that I don't like in the approach above is the adding ajaxResponseMiddleware function in each route.
So what do you think about this approach? May you advise improvements or share your experience.
middleware is just a function function (req, res, next) {}
var express = require('express');
var app = express();
// this is the middleware, you can separate to new js file if you want
function jsonMiddleware(req, res, next) {
res.json_v2 = function (code, data) {
if(!data) {
data = code;
code = 200;
}
// place your modification code here
//
//
res.json(code, data)
}
next();
}
app.use(jsonMiddleware); // Note: this should above app.use(app.router)
app.use(app.router);
app.get('/ajax1', function (req, res) {
res.json_v2({
name: 'ajax1'
})
});
app.listen(3000);

Resources