I am following this tutorial to host a Rest API at my openshift account:
Day 27: Restify–Build Correct REST Web Services in Node.js
As per my requirements I made few changes, below is the code:
server.js
var restify = require('restify');
var mongojs = require('mongojs');
var ip_addr = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';
var port = process.env.OPENSHIFT_NODEJS_PORT || 8080;
var server = restify.createServer({name: 'bemeta'});
server.use(restify.queryParser());
server.use(restify.bodyParser());
server.use(restify.CORS());
server.listen(port, ip_addr, function(){
console.log(server.name + ' listening at url ' + server.url);
});
var connectionString = '127.0.0.1:27017/bemeta';
if(process.env.OPENSHIFT_MONGODB_DB_PASSWORD){
connectionString = process.env.OPENSHIFT_MONGODB_DB_USERNAME + ':' +
process.env.OPENSHIFT_MONGODB_DB_PASSWORD + '#' +
process.env.OPENSHIFT_MONGODB_DB_HOST + ':' +
process.env.OPENSHIFT_MONGODB_DB_PORT + '/' +
process.env.OPENSHIFT_APP_NAME;
}
var db = mongojs(connectionString, ['bemeta']);
var beRecords = db.collection("be_records");
var PATH = '/be_records';
// get all records
server.get({path: PATH, version:'0.0.1'}, findAllRecords);
// create new record
server.post({path: PATH, version:'0.0.1'}, createRecord);
// defining call backs
function findAllRecords(req, res, next){
res.setHeader('Access-Control-Allow-Origin', '*');
beRecords.find(function(err, docs){
console.log('Response docs ' + docs);
console.log('Error '+ err);
if(docs){
res.send(200, docs);
return next();
}
return next(err);
});
}
function createRecord(req, res, next){
res.setHeader('Access-Control-Allow-Origin', '*');
var beRecord = {};
beRecord.be_id = req.params.be_id;
beRecord.item_title = req.params.item_title;
beRecord.item_description = req.params.item_description;
beRecord.item_link = req.params.item_link;
beRecords.save(beRecord, function(err, docs){
console.log('Response docs ' + docs);
console.log('Error '+ err);
if(docs){
res.send(201, beRecord);
return next();
}
else {
next(err);
}
});
}
When I run it at local and fire a get request via postman by typing below url:
http://127.0.0.1:8080/be_records
I get response as: [], which is correct since I have not inserted any document in respective collection.
But when I run it at my openshift account and fire a get request via postman by typing below url:
http://bemeta-{domain-name}.rhcloud.com/be_records
I get response as:
{
"code": "InternalError",
"message": "auth fails"
}
In my rhc console I see below messages:
==> app-root/logs/mongodb.log <==
Wed Feb 24 01:32:23.543 [conn3] authenticate db: bemeta { authenticate: 1, user: "admin", nonce: "some nonce", key: "some key" }
Wed Feb 24 01:32:23.544 [conn3] auth: couldn't find user admin#bemeta, bemeta.system.users
I am not sure why is it trying to find user - admin#bemeta, might be I am missing something over here, I do not have any such user but I do have an admin user which is used to connect to mongodb.
Here is the snapshot of my db (as shown in RockMongo):
Any ideas?
The auth error was caused by not having the admin user authenticated for accessing the bemeta database (see question comments above for details).
Users can be authenticated using the RockMongo interface as follows:
Select a DB -> More -> Authentication -> Add user.
Related
My backend gets a request to get records from an Azure SQL db. To manage this requests I'm using Express in Nodejs, and Tedious (to connect to DB). When the request to the appropriate route comes in, Tedious opens the connection with db, queries it, and it should send the response back to frontend.
However, the code responds before I have an answer with from the db, and thus when I go to send the real (the actually desired) response, Express tells me it already sent headers back (the dreaded: 'Cannot set headers after they are sent to the client').
After debugging quite a bit (using several console.log(JSON.stringify(resp.headersSent)); ) to see when was the response actually sent, I noticed that it's sent the moment I connect with Azure (see below).
I'm not sure if I'm missing something (though I already checked the documentation for all those programs quite a bit), but how can I control when the response is sent? Or, is there another way of doing this.
I omitted several of the other routes for brevity. Other routes work fine and thus I know code connects well to Azure db, and frontend does query backend correctly. Help is appreciated. Thank you.
const express = require('express');
const cors = require('cors');
const Connection = require('tedious').Connection;
const Request = require('tedious').Request;
const config = {
authentication: {
options: {
userName: "xxxx",
password: "xxxx"
},
type: 'default'
},
server: "xxxx",
options: {
database: "xxxx",
encrypt: true
}
};
const app = express();
app.use(express.json({type: '*/*'}));
app.use(cors({ origin: '*' }));
app.get("/allproj/", function (req, resp) {
const q = `select Title, Report_Date, Project_Number, Phase_Code, Items_No, PId from projec order by PId desc`;
let ansf = [];
const connection = new Connection(config);
connection.on('connect', (err, connection) => {
if (err) {
console.log(err);
} else { //this is the moment the headers are sent,
//seemingly with positive response from connection
queryItems(q);
}
});
queryItems = (q) => {
request = new Request(q, function (err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows pulled');
connection.close();
}
});
request.on('row', function(columns) {
let ans = [];
columns.forEach(function(column) {
ans.push(column.value);
if (ans.length === 6) { // I know each row is 6 cols long
ansf.push(ans);
ans = [];
}
});
console.log('ansf length: ' + ansf.length);
resp.send({ ansf }); // This is the response I would like to return
});
request.on('done', function(rowCount) {
console.log(rowCount + ' rows returned');
connection.close();
});
connection.execSql(request);
};
resp.redirect("/");
});
app.listen(3000, process.env.IP, function() {
console.log("Started OK...");
});
Remove resp.redirect("/");
As it is already transferring your request to "/" and when control come at resp.send({ansf}), It gives you error.
I am experimenting with the softlayer-client api wrapper in my Node Express application. My goal is to update the VPN password of a User_Customer by calling the updateVpnPassword method on a specific user.
I can construct a call to achieve a VPN password update using request, but I'm not sure it's the best way to achieve the desired result.
Can the softlayer-client module be used to make an similar call to this:
function updateVpnPassword(req, res, next) {
// Construct URL to update VPN
myURL = 'https://' + <userIDAdmin> + ':' + <apiKeyAdmin> + '#api.softlayer.com/rest/v3/SoftLayer_User_Customer/' + <softLayerID> + '/updateVpnPassword/' + <newPassword> + '.json';
request.get({url: myURL}, function (error, response, body) {
console.log('error:', error);
console.log('statusCode:', response && response.statusCode);
console.log('body:', body);
});
next();
}
My initial attempts have been to try variations on this:
function updateVpnPassword(req, res, next) {
// Assuming var client = new SoftLayer();
client
.auth(<userIDAdmin>, <apiKeyAdmin>)
.path('User_Customer', <softLayerID>,'updateVpnPassword')
.parameters(<newPassword>)
.put(function(err,result){
console.log(result);
if (err) {
next(err); // Pass errors to Express.
}
else {
// update successful
}
});
next();
}
But the console log gives an error response like
{ message: { error: 'Internal Error', code: 'SoftLayer_Exception_Public' } }.
I expect a TRUE or FALSE response, to indicate the whether the update is successful.
A similar python client can be found here but I require an implementation in JS.
I'm not familiar with nodejs but I installed the package softlayer-node and run your second code and it worked.
I also created the following script and I got TRUE
var username = 'set me';
var apikey = 'set me';
var userId = 1111111;
var SoftLayer = require('softlayer-node');
var client = new SoftLayer();
client
.auth(username, apikey)
.path('User_Custome', userId, 'updateVpnPassword')
.parameters('P#ssword123')
.put()
.then(function(result) {
console.log(result);
}, function(error) {
console.log(error);
});
node command:
$ node updateVpnPassword.js
true
Did you tried by sending that request using curl or any other REST client like postman?
If you get the same error then I recommend you submit a ticket and provide information like the id of users you are trying to update the vpn password and the user with which you are sending the request.
i'm trying to get client hostname by getting their ip and then use dns.reverse to do the thing, it works, i'm getting the ip but i don't client hostname. Am i misunderstand something or is there the better way to do.
queue2: function(req, res){
var mac = req.param('mac');
var ip = req.connection.remoteAddress;
dns.lookup(ip,function onLookup(err, addresses){
console.log('Address :' + addresses);
dns.reverse(addresses, function(err, hostname){
Q_list.query("CALL GetQueuePlay('00')", function (err, result) {
if (err){
return res.send(err);
}
console.log(result);
console.log(addresses+ ' : ' + JSON.stringify(hostname));
return res.view('kue/kue',{q_play_list:result});
});
});
});
},
I'm writing a REST API in Sails.js and alongside the regular HTTP routes, I need the application to listen for notifications on a socket from Salesforce.
I have a controller with some logic but I don't know how to get it to subscribe to the socket on startup, so right now nothing is reaching it.
Controller:
pushTopicHandler: function(req, res) {
if (!req.isSocket) {
return res.badRequest();
}
var nforce = require('nforce');
var org = nforce.createConnection({
clientId: sails.config.client_id,
clientSecret: sails.config.client_secret,
redirectUri: sails.config.callback_url + '/oauth/_callback',
mode: 'multi',
environment: 'sandbox'
});
org.authenticate({ username: sails.config.sfUsername, password: sails.config.sfPassword }, function(err, oauth) {
if(err) return res.serverError(err);
var str = org.stream({ topic: sails.config.push_topic, oauth: oauth });
str.on('connect', function(){
console.log('Connected to pushtopic: ' + sails.config.push_topic);
});
str.on('error', function(error) {
console.log('Error received from pushtopic: ' + error);
});
str.on('data', function(data) {
console.log('Received the following from pushtopic ---');
console.log(data);
});
});
}
Sails has a bootstrap.js file which lets you write anything you want to run before the server lifts.
I was able to subscribe to the push topic in a small function before the cb() in that file and it works, the server starts the REST API normally and it's still listening for events.
below is my Accounts.js Module.
var Accounts = function(){
return{
registerNewUser : function(req,res){
console.log(req.body);
var email = req.body.email;
var password = req.body.password;
if(email === undefined || password === undefined){
res.status(400).end('Required Fields Missing');
}
else{
email = email.trim();
password = password.trim();
console.log('lengths = ', email.length, ' password length = ', password.length);
if(email.length <= 0 || password.length <= 0){
res.status(400).end('Bad Request');
}
else{
res.status(200).end('ok');
}
}
}
}
}
module.exports = new Accounts();
Mocha UnitTests.js
var request = require('supertest');
var app = require('../express-app');
describe('Testing Route to Register New User', function(){
var server;
beforeEach(function(){
server = app.startServer();
});
afterEach(function(done){
server.close();
done();
});
it('Missing required fields test', function(done){
request(app).post('/register',{
}).expect(400).end(done);
}) ;
it('Empty field test',function(done){
request(app).post('/register',{
email:"",
password:" "
}).expect(400).end(done);
});
it('Should accept the correct email and password',function(done){
request(app).post('/register',{
email:"email",
password:"alskdjfs"
}).expect(200).end(done);
});
});
Mocha Output:
Testing Route to Register New User
API Server listening on port 3000
{}
✓ Missing required fields test
API Server listening on port 3000
{}
✓ Empty field test
API Server listening on port 3000
{}
1) Should accept the correct email and password
2 passing (65ms)
1 failing
1) Testing Route to Register New User Should accept the correct email and password:
Error: expected 200 "OK", got 400 "Bad Request"
at Test._assertStatus (node_modules/supertest/lib/test.js:232:12)
at Test._assertFunction (node_modules/supertest/lib/test.js:247:11)
at Test.assert (node_modules/supertest/lib/test.js:148:18)
at Server.assert (node_modules/supertest/lib/test.js:127:12)
at emitCloseNT (net.js:1521:8)
I have tested the above route using curl cli and it works as expected , similarly it works as expected from the browser form post , i do not know why mocha fails it ?
Can some one please throw light where i am doing wrong to fix this issue.
Regards
You are probably sending the data in a wrong way. Try this
it('Should accept the correct email and password',function(done){
var data = {
email:"email",
password:"alskdjfs"
};
request(app).post('/register').send(data).expect(200).end(done);
});