using bluebird promises with express to make API calls - api

I'm trying to get different chunks of data from a trello API using bluebird promises library. In my express router I'm using middleware isLoggedIn, and getBoards, which body looks something like:
trello.get("/1/members/me/boards") // resolves with array of board objects
.each((board) => {
// do some async stuff like saving board to db or other api calls, based on retrieved board
.catch(err => console.error('ERR: fetching boards error - ${err.message}'))
})
The question is: I want to redirect (res.redirect('/')) only when all boards were retrieved and saved. How can I do that? Where should I place xres.redirect('/') expression?

I think you need something like:
var Promise = require('bluebird');
var promises = [];
trello.get("/1/members/me/boards") // resolves with array of board objects
.each((board) => {
//
promises.push( /*some promisified async call that return a promise, saving data in db or whatever asynchronous action. The important bit is that this operation must return a Promise. */ );
});
//So now we have an array of promises. The async calls are getting done, but it will take time, so we work with the promises:
Promise.all(promises).catch(console.log).then( function(results){
/*This will fire only when all the promises are fullfiled. results is an array with the result of every async call to trello. */
res.redirect('/'); //now we are safe to redirect, all data is saved
} );
EDIT:
Actually, you can avoid some boilerplate code using map instead of each:
trello.get("/1/members/me/boards") // resolves with array of board objects
.map((board) => {
return somePromisifiedSaveToDbFunction(board);
}).all(promises).catch(console.log).then( function(results){
res.redirect('/');
} );

Related

Using promises in Mongoose

I am new to the Promise method used to retrieve multiple database records at the same time and I want to rewrite my existing code to use promises
I have this piece of code in Express:
getController.getData = function(req,res, collection, pagerender) {
var id = req.params.id;
collection.find({}, function(err, docs){
if(err) res.json(err);
else res.render(pagerender, {data:docs, ADusername: req.session.user_id, id: req.params.id});
console.log(docs);
});
};
Now I want to use promises here, so I can do more queries to the database. Anyone know how I can get this done?
First, check if collection.find({}) returns a promise. If it does, then you can call your code like:
collection.find({}).
then(function(docs){
res.render(pagerender, {data:docs, ADusername: req.session.user_id, id: req.params.id});
})
.catch( function(err) {
res.json(err);
})
If you want more calls here, just create new DB call and add another .then block.
I suggest you read the documentation on promises, just to get a general feeling about them (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then). You will also see how you can handle both success and rejection in the same function if you want.

Correct usage of getters in vuex

I'm currently developing an app with vue v2, and something got me thinking. It's kind of hard to find information for good practices so I decided I will ask here.
I have a laravel api and vue for front end. Until now my models were such that will hold only a few objects (< 100), so I just put the in the state, and get what ever needed with a getter. Now I have a model that will hold > 10000 objects, so putting them all into the state is pretty much out the topic. The way I solve this problem is a have with action that gets a single object from the api by id, and put it in the state, after a check if its not in there already. The check happens with a getter that I'm also using when I need this object. So I have similar structure:
​
// mutation
[mutation_types.FETCH_SOMETHING](state, {something}) {
if (!this.getters.getSomethingById(something.id)) {
state.somethings.push(something)
}
}
// action
const {data} = await axios.get('~route~')
commit(mutation_types.FETCH_SOMETHING, {something: data.something})
// getter
getSomethingById: state => id => {
return state.somethings.find(something => something.id === id)
}
​
So this is working, but there are 2 problems that I see. The first is every time when I need a something I should call the dispatch to get the item from the api into the state and then the getter to get the actual object and the second problem is the check is happening after the api call, so even if I have this specific something in the state, I'm doing a request for it.
A way to fix both of those problems that I though of calling the just working with the getter, which will check that state, if the searched ID is found in there it will be returned, if not, the dispatch will get it from the api and then return it.
I feel like I'm adding logic to the getter that doesn't belong there, but I can't think of another way to achieve this. Is there something that I'm missing / doing wrong somewhere?
Take advantage of the async nature of vuex actions and promises. Do the check for existence directly in the action along with the api call if needed:
state: {
items: []
}
mutations: {
addItem: (state, item) => {
state.items.push(item)
}
}
actions: {
fetchItem: async (context, id) => {
let item = context.state.items.find(i => i.id === id)
if (!item) {
item = await axios.get('/example/' + id).then(response => {
context.state.commit('addItem', response.data)
return response.data
})
}
return item
}
}

Angular multiple rest api request

im new on Angular and have a question.
I need to call 2 API Rest, on second API i need result of first API.
I have this code:
ngOnInit() {
this.Jarwis.getmyinfo()
.subscribe(
// data => console.log(data),
data => this.Getmyinfo = data,
error => console.log(error),
);
this.Jarwis.showazienda(id_azienda).subscribe(
// data => console.log(data),
data => this.Showazienda = data,
error => console.log(error),
);
}
This is a call to API rest in Jarwis:
getmyinfo(): Observable {
return this.http.get(${this.baseUrl}/me);
}
showazienda(data): Observable {
return this.http.get(${this.baseUrl}/showazienda/ + data);
}
getmyinfo is first HTTP REQUEST and where i need to get id_azienda for second HTTP REQUEST (showazienda)
I think need map result of first http request in json and get result of id_azienda but im not able to do it.
If i set 1 in the parameters of showazienda im able to get and show info of API.
For observables, you use the ".flatMap" to chain multiple async actions together (this is very similar to the promises ".then"). The flatMap allows you to used to chain multiple async requests together and have them execute one by one in order.
Here is a good explanation of flatMap.
So for your example, you would do something like this:
ngOnInit() {
this.Jarwis.getmyinfo()
.flatMap(
(data) => {
this.Getmyinfo = data;
// get id_azienda from data
return this.Jarwis.showazienda(id_azienda);
}
).subscribe(
// data => console.log(data),
data => this.Showazienda = data,
error => console.log(error),
);
}
This example code will first send the "getmyinfo()" request. Once the response is received the ".flatMap" will be called with the data received from "getmyinfo()". You can then used this data to get the "id_azienda". Then you can make the second request to "showazienda". The observable returned from "showazienda()" needs to be returned in the flatMap. Then you subscribe to the modified observable and the data you receive will be the result from the "showazienda()" request.

FETCH API return undefined

I want to use Fetch API but i don' t really understand it's mecanism.
I have an in my HTML and i want to assign the result of my fetch with this code :
const weather = "http://api.apixu.com/v1/current.json?key=cba287f271e44f88a60143926172803&q=Paris";
const array = [];
fetch(weather)
.then(blob => blob.json())
.then(data => {
array.push(data.current.humidity)
console.log(array[0])
}
);
document.querySelector('h1').innerHTML = array[0];
i have the result with the console.log but the returns "undefined". can you explain why ?
thanks a lot
This is because the call to the API is asynchronous, meaning that the code is not executed just line by line as you write it. The callback only runs as soon as the call to the API has finished, basically meaning that
data => {
array.push(data.current.humidity)
console.log(array[0])
}
runs after
document.querySelector('h1').innerHTML = array[0];
So when you try to set your h1, array is still empty. If you want to set it as soon the data is available, you have to do it within the callback function:
data => {
array.push(data.current.humidity)
document.querySelector('h1').innerHTML = array[0];
}
This might seem weird at first, but keep in mind that you're only registering an anonymous function but not running it yet. You just define the function that you want to trigger as soon as something happens, in this case: when your API call has finished.

What is the role of exec() and next() call in cascade delete in mongoose middleware?

I'm new to using mongoose middleware and don't know if I'm following it well. Here is the purpose. After saving department, I want to populate university and save departmentId inside university object.
DepartmentSchema.post('save', function(next) {
var departmentId = this._id;
University.findOne({
_id: this.university
}, function(err, university) {
if (!university.departments) {
university.departments = [];
}
university.departments.push(new ObjectId(departmentId));
university.save(function(err) {
if (err) return console.log('err-->' + err);
// saved!
});
});
});
This is working fine but I'm not sure why in Cascade style delete in Mongoose they have used exec() and next() calls. Could you please tell me the purpose of these calls? I don't know what they do and not able to find relevant documentation. I just want to make sure I'm not missing anything.
clientSchema.pre('remove', function(next) {
// 'this' is the client being removed. Provide callbacks here if you want
// to be notified of the calls' result.
Sweepstakes.remove({
client_id: this._id
}).exec();
Submission.remove({
client_id: this._id
}).exec();
next();
});
Post middleware doesn't have reference to the next function and you cant do any flow control. Its actually passing the department that just got saved, so your code can be something like this:
DepartmentSchema.post('save', function(department) {
var departmentId = department._id;
In pre middleware you have access to the next middleware in the order of execution. Which is the order of definition on a particular hook.
// hook two middlewares before the execution of the save method
schema.pre('save', pre1);
schema.pre('save', pre2);
function pre1(next) {
// next is a reference to pre2 here
next()
}
function pre2(next) {
// next will reference the hooked method, in this case its 'save'
next(new Error('something went wrong');
}
// somewhere else in the code
MyModel.save(function(err, doc) {
//It'll get an error passed from pre2
});
Mongoose also gives you the ability to execute pre middlewares in parallel, in this case all middlewares will be executed in parallel but hooked method will not execute till the done is called from each middleware.
As for the exec() function, there are two ways of executing a query in Mongoose, either pass a callback to the query or chain it with an exec(): User.remove(criteria, callback) or User.remove(criteria).exec(callback), if you don't pass a callback to the query, it'll return a query object and it won't execute unless you chain it with exec()