I'm new to nodejs and this is my first app. I am trying to use a nodejs API called event registry to get some data. Implementation below:
app.get('/eventregistry', function(req,res){
console.log("dfsdfdf");
var er = new erBase.EventRegistry({apiKey: "API Key"});
er.getConceptUri("syria").then((conceptUri) => {
var q = new erBase.QueryArticlesIter(er, {conceptUri: conceptUri, sortBy: "date"});
q.execQuery((items) => {
for(var item of items) {
console.info(item);
}
})
});
});
My problem is when I run the server and go to the route nothing happens. My event package is installed and required as well. What am I doing wrong?
you must send a response back to client using that res object in your callback function:
app.get('/eventregistry', function(req,res){
console.log("dfsdfdf");
var er = new erBase.EventRegistry({apiKey: "API Key"});
er.getConceptUri("syria").then((conceptUri) => {
var q = new erBase.QueryArticlesIter(er, {conceptUri: conceptUri, sortBy: "date"});
q.execQuery((items) => {
for(var item of items) {
console.info(item);
}
res.status(200).json(items); // as example
})
});
});
I highly recommend you reading express documentation, exceptionally their Response Object part.
Related
I am trying to get data from another database before reading data in the table. However, I can't seem to find a way to access it properly.
The best I've got so far is based on some other examples both on Microsoft's documentation and on StackOverflow but they all seem to fail.
table.read(function (context) {
var results = context.tables("table2").read();
var text = results[0].column;
context.query.where({ columnName: text });
return context.execute();
});
I get an error when doing this saying that column doesn't exist.
As per your description, if I do not misunderstand, you want to query table2 in table1 operations in EasyTables scripts.
we can leverage "use()" to custom middleware to specify middleware to be executed for every request against the table as the description on the document of azure-mobile-apps sdk at
E.G.
var queries = require('azure-mobile-apps/src/query');
var insertMiddleware = function(req,res,next){
var table = req.azureMobile.tables('table2'),
query = queries.create('table2')
.where({ TestProperty : req.body.testproperty });
table.read(query).then(function(results) {
if(results){
req.someStoreData = somehander(results); //some hander operations here to get what you want to store and will use in next step
next();
}else{
res.send("no data");
}
});
};
table.insert.use(insertMiddleware, table.operation);
table.insert(function (context) {
console.log(context.req.someStoreData);
return context.execute();
});
More example:
async function filterByAllowedDomain(context) {
var domains = await context.tables('domains')
.where({ allowed: true })
.read();
var categories = await context.tables('categories')
.where(function (ids) {
return this.domainId in ids;
}, domains.map(d => d.id))
.read();
context.query.where(function (ids) {
return this.categoryId in ids;
}, categories.map(c => c.id));
return context.execute(); }
The tables module in azure-mobile-apps-node sdk contains functionality for adding tables to an Azure Mobile App. It returns a router that can be attached to an express app with some additional functions for registering tables. Which actually leverage Azure SQL (SQL Server database service on Azure).
Hope it helps.
I have a repetitive task that I have to do at regular intervals. Basically, I need to enter the website, get some values from different tables then write them on spreadsheet. By using these values, make some calculation, prepare a report etc.
I would like to create a helper bot because this is straight forward task to do.
I can basically get information by opening up console (while I am on the related page) and by using DOM or Jquery I am fetching data easily.
I would like to take it a step further and create an application on Node.js (without entering related website, I will send my bot to related page and do same actions that I do on console.)
I started to write something with cheerio. However, at some point my bot needs to click a button (in order to change table). I searched but couldn't find the way.
My question is "clicking a button on server side (change the table) and fetch data from that table is possible ?"
If do you know better way to create this kind of bot, please make suggestion.
var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var app = express();
app.get('/scrape', (req, res) => {
url = 'http://www.imdb.com/title/tt1229340/';
request(url, function(error, response, html){
if(!error){
var $ = cheerio.load(html);
var title, release;
var json = { title : "", release : ""};
$('.header').filter(() => {
var data = $(this);
title = data.children().first().text();
release = data.children().last().children().text();
json.title = title;
json.release = release;
})
// This is not possible
$( "#target" ).click(function() {
alert( "Handler for .click() called." );
});
}
fs.writeFile('output.json', JSON.stringify(json, null, 4), (err) => {
console.log('File successfully written!);
})
res.send('Check your console!')
}) ;
})
app.listen('8080');
edit: The Answer of this question is "Use Zombie"
Now I have another question related to this one.
I am trying to learn & use zombie. I could
connect to website
go to necessary table
print console all tds
However by using this method, I could only get really messed up string. (All tds were printed without any whitespace, no chance to clean out, basically I want to put all tds in an array. How can I do that ?)
browser.visit(url, () => {
var result = browser.text('table > tbody.bodyName td');
console.log(result);
})
I'd suggest you try using a headless browser such as Phantom.js or Zombie for this purpose. What you're trying to do above is assign a click handler to an element in Cheerio, this won't work!
You should be able to click a button based on the element selector in Zombie.js.
There's a browser.pressButton command in Zombie.js for this purpose.
Here's some sample code using zombie.js, in this case clicking a link..
const Browser = require('zombie');
const url = 'http://www.imdb.com/title/tt1229340/';
let browser = new Browser();
browser.visit(url).then(() => {
console.log(`Visited ${url}..`);
browser.clickLink("FULL CAST AND CREW").then(() => {
console.log('Clicked link..');
browser.dump();
});
}).catch(error => {
console.error(`Error occurred visiting ${url}`);
});
As for the next part of the question, we can select elements using zombie.js and get an array of their text content:
const Browser = require('zombie');
const url = 'http://www.imdb.com/title/tt1229340/';
let browser = new Browser();
browser.visit(url).then(() => {
console.log(`Visited ${url}..`);
var result = browser.queryAll('.cast_list td');
var cellTextArray = result.map(r => r.textContent.trim())
.filter(text => text && (text || '').length > 3);
console.log(cellTextArray);
}).catch(error => {
console.error(`Error occurred visiting ${url}`);
});
It's the first time that I work with evernote,
Like the example given in the JS SDK, I create my client with the token that I get from the OAuth and I get all the notebooks of my current user so it was good for me.
But I'm facing a problem that I can't understand, when I use any method of my shared store it throw an Thrift exception with error code 12 and giving the shard id in the message.
I know that 12 error code is that the shard is temporary unavailable..
But I know that it's another thing because it's not temporary...
I have a full access api key, it work with the note store, did I miss something ?
// This is the example in the JS SDK
var linkedNotebook = noteStore.listLinkedNotebooks()
.then(function(linkedNotebooks) {
// just pick the first LinkedNotebook for this example
return client.getSharedNoteStore(linkedNotebooks[0]);
}).then(function(sharedNoteStore) {
// /!\ There is the problem, throw Thrift exception !
return sharedNoteStore.listNotebooks().then(function(notebooks) {
return sharedNoteStore.listTagsByNotebook(notebooks[0].guid);
}).then(function(tags) {
// tags here is a list of Tag objects
});
});
this seems to be an error with the SDK. I created a PR (https://github.com/evernote/evernote-sdk-js/pull/90).
You can work around this by using authenticateToSharedNotebook yourself.
const client = new Evernote.Client({ token, sandbox });
const noteStore = client.getNoteStore();
const notebooks = await noteStore
.listLinkedNotebooks()
.catch(err => console.error(err));
const notebook = notebooks.find(x => x.guid === guid);
const { authenticationToken } = await client
.getNoteStore(notebook.noteStoreUrl)
.authenticateToSharedNotebook(notebook.sharedNotebookGlobalId);
const client2 = new Evernote.Client({
token: authenticationToken,
sandbox
});
const noteStore2 = client2.getNoteStore();
const [notebook2] = await noteStore2.listNotebooks();
noteStore2.listTagsByNotebook(notebook2.guid)
I have the following code that does not work currently.
var config = require('./libs/sequelize-lib.js');
var connection = config.getSequelizeConnection();//Choosing to not pass in variable this time since this should only run via script.
var models = config.setModels(connection);//Creates live references to the models.
//Alter table as needed but do NOT force the change. If an error occurs we will fix manually.
connection.sync({ alter: true, force: false }).then(function() {
models.users.create({
name: 'joe',
loggedIn: true
}).then( task => {
console.log("saved user!!!!!");
});
process.exit();//close the nodeJS Script
}).catch(function(error) {
console.log(error);
});
sequelize-lib.js
var Sequelize = require('sequelize');
exports.getSequelizeConnection = function(stage){
var argv = require('minimist')(process.argv.slice(2)); //If this file is being used in a script, this will attempt to get information from the argument stage passed if it exists
//Change connection settings based on stage variable. Assume localhost by default.
var dbname = argv['stage'] ? argv['stage']+"_db" : 'localdb';
var dbuser = argv['stage'] ? process.env.RDS_USERNAME : 'admin';
var dbpass = argv['stage'] ? process.env.RDS_PASSWORD : 'local123';
var dbhost = argv['stage'] ? "database-"+argv['stage']+".whatever.com" : 'localhost';
//If state variable used during require overide any arguments passed.
if(stage){
dbname = stage+"_db";
dbuser = process.env.RDS_USERNAME
dbpass = process.env.RDS_PASSWORD
dbhost = "database-"+stage+".whatever.com"
}
var connection = new Sequelize(dbname,dbuser,dbpass, {
dialect: 'mysql',
operatorsAliases: false, //This gets rid of a sequelize deprecated warning , refer https://github.com/sequelize/sequelize/issues/8417
host: dbhost
});
return connection;
}
exports.setModels = function(connection){
//Import all the known models for the project.
const fs = require('fs');
const dir = __dirname+'/../models';
var models = {}; //empty model object for adding model instances in file loop below.
//#JA - Wait until this function finishes ~ hence readdirSync vs regular readdir which is async
fs.readdirSync(dir).forEach(file => {
console.log(file);
//Split the .js part of the filename
var arr = file.split(".");
var name = arr[0].toLowerCase();
//Create a modle object using the filename as the reference without the .js pointing to a created sequelize instance of the file.
models[name] = connection.import(__dirname + "/../models/"+file);
})
//Showcase the final model.
console.log(models);
return models; //This returns a model with reference to the sequelize models
}
I can't get the create command to work however with this setup. My guess is the variables must not be passing through correctly somehow. I'm not sure what I'm doing wrong?
The create command definitely works because if in the sequelize-lib.js I modify the setModels function to this...
exports.setModels = function(connection){
//Import all the known models for the project.
const fs = require('fs');
const dir = __dirname+'/../models';
var models = {}; //empty model object for adding model instances in file loop below.
//#JA - Wait until this function finishes ~ hence readdirSync vs regular readdir which is async
fs.readdirSync(dir).forEach(file => {
console.log(file);
//Split the .js part of the filename
var arr = file.split(".");
var name = arr[0].toLowerCase();
//Create a modle object using the filename as the reference without the .js pointing to a created sequelize instance of the file.
models[name] = connection.import(__dirname + "/../models/"+file);
models[name].create({
"name":"joe",
"loggedIn":true
});
})
//Showcase the final model.
console.log(models);
return models; //This returns a model with reference to the sequelize models
}
Then it works and I see the item added to the database! (refer to proof image below)
Take note, I am simply running create on the variable at this point. What am I doing wrong where the model object is not passing between files correctly? Weird part is I don't get any errors thrown in the main file?? It's as if everything is defined but empty or something and the command is never run and nothing added to the database.
I tried this in the main file also and no luck.
models["users"].create({
name: 'joe',
loggedIn: true
}).then( task => {
console.log("saved user!!!!!");
});
The purpose of this all is to read models automatically from the model directory and create instances that are ready to go for every model, even if new one's are added in the future.
UPDATE::
So I did another test that was interesting, it seems that the create function won't work in the .then() function of the sync command. It looks like it was passing it correctly though. After changing the front page to this...
var config = require('./libs/sequelize-lib.js');
var connection = config.getSequelizeConnection();//Choosing to not pass in variable this time since this should only run via script.
var models = config.setModels(connection);//Creates live references to the models using connection previosly created.
models["users"].create({
"name":"joe",
"loggedIn":true
});
//Alter table as needed but do NOT force the change. If an error occurs we will fix manually.
connection.sync({ alter: true, force: false }).then(function() {
process.exit();//close the nodeJS Script
}).catch(function(error) {
console.log(error);
});
Doing this seems to get create to work. I'm not sure if this is good form or not though since the database might not be created at this point? I need a way to get it to work in the sync function.
Well I answered my question finally, but I'm not sure I like the answer.
var config = require('./libs/sequelize-lib.js');
var connection = config.getSequelizeConnection();//Choosing to not pass in variable this time since this should only run via script.
var models = config.setModels(connection);//Creates live references to the models using connection previosly created.
//Alter table as needed but do NOT force the change. If an error occurs we will fix manually.
connection.sync({ alter: false, force: false }).then( () => {
models["users"].create({
"name":"joe",
"loggedIn":true
}).then( user => {
console.log("finished, with user.name="+user.name);
process.exit();
}).catch( error => {
console.log("Error Occured");
console.log(error);
});
}).catch(function(error) {
console.log(error);
});
turns out that process.exit was triggering before create would occur because create happens async. This means that all my code will have to constantly be running through callbacks...which seems like a nightmare a bit. I wonder if there is a better way?
Maybe I'm not understanding the way Promise.promisifyAll works. I'm trying to promisify coinbase package.
Basically, the client's functions are promisified but the accounts returned by those functions don't appear to have the Async version: [TypeError: acc.getTransactionsAsync is not a function].
I've tried passing {multiArgs:true} as options to Promise.promisifyAll() as suggested in an answer to a similar question, but it didn't solve the problem. Any suggestion is appreciated.
Normal way of using the package (works):
var Client = require('coinbase').Client
var client = new Client({
'apiKey': '<snip>',
'apiSecret': '<snip>',
'baseApiUri': 'https://api.sandbox.coinbase.com/v2/',
'tokenUri': 'https://api.sandbox.coinbase.com/oauth/token'
});
//Callbacks
client.getAccounts({}, function(err, accounts) {
accounts.forEach(function(acc) {
acc.getTransactions(null, function(err, txns) {
txns.forEach(function(txn) {
console.log('txn: ' + txn.id);
});
});
});
});
Promisified version not working (getTransactionsAsync is undefined, but the getAccountsAsync returns the accounts correctly):
var Promise = require('bluebird');
var Client = require('coinbase').Client;
var client = new Client({
'apiKey': '<snip>',
'apiSecret': '<snip>',
'baseApiUri': 'https://api.sandbox.coinbase.com/v2/',
'tokenUri': 'https://api.sandbox.coinbase.com/oauth/token'
});
Promise.promisifyAll(client);
//Promises
client.getAccountsAsync({}) //Works perfectly, returns the accounts
.then(function(accounts) {
return Promise.map(accounts, function(acc) {
return acc.getTransactionsAsync(null); //This function call is throwing the TypeError
});
})
.then(function(transactions) {
console.log('Transactions:');
transactions.forEach(function(tx) {
console.log(tx);
});
})
.catch(function(err) {
console.log(err);
});
EDIT:
Looking through the package I want to promisify, I realized that the functions I'm trying to call are from the model objects returned by the package. I think promisifyAll only parses the client functions, and the models are not being processed. I'm just not that well versed on how the parsing is made :(
This is the index.js (module exported)
var Account = require('./lib/model/Account.js'),
Address = require('./lib/model/Address.js'),
Buy = require('./lib/model/Buy.js'),
Checkout = require('./lib/model/Checkout.js'),
Client = require('./lib/Client.js'),
Deposit = require('./lib/model/Deposit.js'),
Merchant = require('./lib/model/Merchant.js'),
Notification = require('./lib/model/Notification.js'),
Order = require('./lib/model/Order.js'),
PaymentMethod = require('./lib/model/PaymentMethod.js'),
Sell = require('./lib/model/Sell.js'),
Transaction = require('./lib/model/Transaction.js'),
User = require('./lib/model/User.js'),
Withdrawal = require('./lib/model/Withdrawal.js');
var model = {
'Account' : Account,
'Address' : Address,
'Buy' : Buy,
'Checkout' : Checkout,
'Deposit' : Deposit,
'Merchant' : Merchant,
'Notification' : Notification,
'Order' : Order,
'PaymentMethod' : PaymentMethod,
'Sell' : Sell,
'Transaction' : Transaction,
'User' : User,
'Withdrawal' : Withdrawal
};
module.exports = {
'Client' : Client,
'model' : model
};
EDIT 2:
The Client requires it's own model modules, so Promise.promisifyAll should as expected with the object's properties without having the previous edit interfering. At this point I think there might be no other option that making my own Promises for all functions I will need that don't live directly under the client.
I think promisifyAll only parses the client functions, and the models are not being processed.
Not exactly. This has nothing to do with how promisifyAll is looking through the methods and properties. Rather, you are explicitly passing only the client methods to be promisified:
var Client = require('coinbase').Client;
var client = new Client(…);
Promise.promisifyAll(client);
There's no link from client to the models. Rather try to call promisifyAll on the whole module, not only the Client class:
var Client = Promise.promisifyAll(require('coinbase')).Client;
or if that doesn't work, Call promisifyAll on both the Client class and the models collection of classes:
var coinbase = require('coinbase');
var Client = Promise.promisifyAll(coinbase.Client);
Promise.promisifyAll(coinbase.model);
So, instead of editing the question again I'm adding my temporary workaround (with a slightly different function call but that had the same problem of not having the Async function). This promisifies the model modules by it's own and I'll need to create them on demand whenever I need an promisified function on the non-promisified version of the models returned by the client.
It's not what I would like to do, since more memory allocation is needed for each model that I want to make a promisified function call. But I prefer this approach over creating new modules for grouping new Promise(...) functions.
If a better solution is suggested I'll still mark that as solved.
var Promise = require('bluebird');
var Client = require('coinbase').Client;
var cbModel = require('coinbase').model;
var client = new Client({
'apiKey': '<snip>',
'apiSecret': '<snip>',
'baseApiUri': 'https://api.sandbox.coinbase.com/v2/',
'tokenUri': 'https://api.sandbox.coinbase.com/oauth/token'
});
Promise.promisifyAll(client);
Promise.promisifyAll(cbModel);
//Promises
client.getAccountAsync('primary')
.then(function(account) {
account = new cbModel.Account(client, account);
return account.getTransactionsAsync(null);
})
.then(function(transactions) {
console.log('Transactions:');
transactions.forEach(function(tx) {
console.log(tx.id);
});
})
.catch(function(err) {
console.log(err);
});