Trouble with Async/Await on APIs response - node.js

Hey guys that's my first app using Node.js and I'm having trouble working with async/ await.
On my index.js I have three methods that depends on each-other, but can't figure out how to do it.
Can someone lend me a hand and teach me in in the work?
async function Millennium_SendSMS() {
// search for orders on Millennium's API
let orders = await new listOrders().listOrders();
// filter orders
let filteredOrders = new filterOrders().filterOrders(orders);
// send sms to the filtered orders
filteredOrders.map(order => {
new sendSmsRequest(order).sendSmsRequest();
})
}
When I try to run the code above, I get an error message from the filterOrders method saying that that the var orders is undefined.
Update:
listOrders class
class listOrders {
listOrders() {
axios.get('http://mill.com/api/millenium_eco/pedido_venda/listapedidos')
.then(listOrders => {
return listOrders;
})
}
}

You haven't returned the promise from listOrders function within your class so there is nothing to resolve for the await function
Add a return statement to listOrders function like below and it would work
class listOrders {
listOrders() {
return axios.get('http://mill.com/api/millenium_eco/pedido_venda/listapedidos')
.then(listOrders => {
return listOrders;
})
}
}

Related

how to use transaction across service in nestjs with typeorm

How can I have a transaction across different service in my project?
I try my code as below but the transaction doesn't rollback while exception threw.
The following code will rollback as expected, but I would like to separate the create logic into corresponding service.
public async createProduct(dto: CreateProductDto): Promise<ProductEntity> {
const product = await this.dataSource.transaction(async (entityManager) => {
dto.price = await this.priceService.createPrice(
entityManager,
dto.unitPrice,
);
throw new BadRequestException('bad');
return await entityManager
.getRepository(ProductEntity)
.create({ ...dto })
.save();
});
console.log(product);
return product;
}
Thanks everyone, I just found the problem is I can't chain the save() right after create() which will call the entity's save() fn instead of the entityManager's one, and start a new transaction.
async createPrice(dto, entityManager){
//wrong code
return entityManager.create(PriceEntity, {...}).save();
//works
const price = entityManager.create(PriceEntity, {...});
return entityManager.save(price);
}
}
try to add #Transactional() decorator before insert function from your services typeorm transaction/
typeorm-transactional-cls-hooked
#Transactional()
public async createProduct(...) {
...
}

how to get [chrome.instanceID.getID] , [chrome.storage.sync.get] by async & await?

How do you get the information for the Chrome extension by using async and await?
[chrome.instanceID.getID]
[chrome.storage.sync.get]
We tried this code:
async function test()
{
let _r = await chrome.instanceID.getID();
return _r;
}
let _pc_id = test();
but _pc_id returns a promise. We find no way to get the value in it. How should we do this?
You can get the instanceID like this, but can't store it in a variable to use it out of scope of the promise, AFAIK. You may want to read this: saving data from promise in a variable
If you want to use the returned value of Promise you need to do it in the promise or in .then()s after the promise, at least that is how I do it.
chrome.instanceID.getID example:
chrome.instanceID.getID((instance_id) => {
console.log(instance_id);
// Execute your other related code here
});
or
var promise = chrome.instanceID.getID();
promise.then((instance_id) => {
console.log(instance_id);
// Execute your other related code here
});
or
chrome.instanceID.getID()
.then((instance_id) => {
console.log(instance_id);
// Execute your other related code here
});
chrome.storage.sync.get example:
chrome.storage.sync.get('myKey', function(items) {
var key = items.myKey;
// Below code is an example, change it to your needs
if (key) {
console.log(key)
} else {
key = createKey(); // a custom function that generates keys
chrome.storage.sync.set({myKey: key}, function () {
console.log(key);
});
}
};

Returning a value from a mix of async/sync function from a provider (different script) to express server

Apologies for asking this question - I know there are tons of information about async functions out there but I seem to have tried everything and cannot find a solution..
First of all let me outline the architecture of my program. There are two scripts: a main server script (node.js, express), which processes GET requests and provider script, which deals with the blockchain in the background to return some values. The server script is responsible for invoking a method that returns a value from the provider. The provider does all the work.
The snippet of the provider script:
getInfo(index, account, key) {
//Waiting on an asynchronous method, which does some work in the blockchain in the background; everything functions as it should be
try {
await this.getBlockchain
(
index
, account
, key
).then(result => {
// Here instead I invoke a SYNCHRONOUS method, which simply formats the response in a correct way
const reply = this.sendReply(result)
console.log(reply) //Logs the correct reply in the format in which the server is expecting it
return reply;
});
}
catch (error) {
return { error: 003, result: false };
}
}
The snippet of the server script:
server.get("/getAccount", async (req, res) => {
let index = req.query.index;
let account = req.query.account;
let key = req.query.key;
// Here I also check for the validity of the query values, irrelevant to this issue
// The provider class is imported as provider, hence, the provider.method (this has been tested many times before)
try {
await provider.getInfo(index, account, key).then(reply => {
const { error: infoError, result: infoValue } = reply
if (infoError == false) {
res.send(`${infoValue}`);
} else {
res.send(`${infoError}`);
};
});
}
catch (error) {
res.send("008");
}
}
);
I honestly have no idea how to approach this; I tried self-contained async function on the server side as well as different syntax but the reply is always undefined even though the reply from a synchronous call in the provider is correct.
Could someone help me to understand what I'm doing wrong? This is my first time working with async with numerous scripts and functions and I'm finding it very confusing.
Thank you so much!
With your current structure, you need to return the result of the await so that the top level of your function is returning something from the async function.
async getInfo(index, account, key) {
try {
let retVal = await this.getBlockchain(index, account, key).then(result => {
return this.sendReply(result);
});
return retVal;
} catch (error) {
return { error: 003, result: false };
}
}
But, really, it's a better coding style to not mix await and .then() and to just go with one style like this:
async getInfo(index, account, key) {
try {
let result = await this.getBlockchain(index, account, key);
return this.sendReply(result);
} catch (error) {
return { error: 003, result: false };
}
}
Note, this function never rejects because it's catching its own rejections and turning it into a resolved value. So, the caller cannot use .catch() to see errors. The caller must always check for the error property in the resolved object. This is not usually how you program with promises. It can be made to work, but often does not meet the expectations of the caller (as errors are usually communicated back via rejected promises).
This has to be a dup. but... Don't mix await and .then.
You simply try/catch around await.
try {
const reply = await provider.getInfo(index, account, key);
const { error: infoError, result: infoValue } = reply
if (infoError == false) {
res.send(`${infoValue}`);
} else {
res.send(`${infoError}`);
};
} catch (error) {
res.send(500);
}

rxjs subscription returning duplicates

After making a subscription from Angular service, the returning results are bunch of duplicates. For every call, the number of duplicates increase by one.
I tried console logging the results at various stages of the app. The duplicates are returned immediately after the promise get rendered
Angular Service code:
GetUserPendingApprovals(userid: string) {
let approvalsPending: any[] = [];
this.http
.get<{message, approvals: any}>(`/api/approvals/${userid}`)
.subscribe(approvals => {
console.log(approvals.approvals);
approvalsPending = approvals.approvals;
this.approvalsUpdated.next(approvalsPending);
approvalsPending = [];
});
}
getUserPendingApprovalsUpdateListener() {
return this.approvalsUpdated.asObservable();
}
node end point:
app.get("/api/approvals/:userid", (req, res, next) => {
// const urlData = req.params.userId;
//console.log(urlData);
const query = datastore
.createQuery('approvals')
.filter('src', '=', req.params.userid);
query.run().then(approvals => {
approvals.forEach(approval => console.log(approval));
console.log(approvals[0].length);
res.status(200).json(
{
message: "Request was processed successfully!",
approvals: approvals[0]
}
);
})
})
The console logging on node endpoint returns a proper count value for the results being queries for. However, console logging of the same results on the Angular service code returns duplicates and the number of duplicates increase by one for every call. Example: 1st call - 2 duplicates, 2nd call - 3 duplicates, 3rd call - 3 duplicates and so on.
More information...
I am making nested subscription from my angular component. Something like below -
ngOnInit() {
this.activatedRoute.params
.subscribe(
(params: Params) => {
....some code goes here...
this.revenueService.GetUserInvoicesThisWeek(this.userid);
this.currentWeekInvoicesSub = this.revenueService.GetUserInvoicesThisWeekListener()
.subscribe((revenueInfo: Revenue[]) => {
....some code goes here...
});
this.currentDayInvoicesSub = this.revenueService.GetUserInvoicesTodayListener()
.subscribe((todayRevenueInfo: Revenue[]) => {
....some code goes here...
});
this.approvalsService.GetUserPendingApprovals(this.userid);
this.approvalsSub = this.approvalsService.getUserApprovalsUpdateListener()
.subscribe((approvalsPending: any[]) => {
....some code goes here...
});
});
}
The last subscription is where i am facing problems. But i am pretty sure the rendered promise right after the node endpoint call is returning duplicates. Something which i mentioned in the beginning of this question.
Doubts:
What would be the root cause for these duplicates?
How to resolve this issue?
You are subscribing everytime this function gets called, so you're making a duplicate subscription everytime you change your route.
GetUserPendingApprovals(userid: string) {
let approvalsPending: any[] = [];
this.http
.get<{message, approvals: any}>(`/api/approvals/${userid}`)
.subscribe(approvals => {
console.log(approvals.approvals);
approvalsPending = approvals.approvals;
this.approvalsUpdated.next(approvalsPending);
approvalsPending = [];
});
}
Subscribe in the component instead in the service to fix this issue.
GetUserPendingApprovals(userid: string) {
return this.http
.get<{message, approvals: any}>(`/api/approvals/${userid}`)
}
Component ts:
ngOnInit(){
this.aprovalSub = this.approvalsService.GetUserPendingApprovals(this.userid);
.subscribe(approvals => {
approvalsService.approvalsPending = approvals.approvals;
approvalsService.approvalsUpdated.next(approvalsPending);
});
}
ngOnDestroy(){
if(this.aprovalSub !== undefined) this.aprovalSub.unsubscribe()
}
Clean up subscriptions when component gets destroyed or they will stay in memory and you will have subscriptions taking up memory.

Empty AWS S3 bucket of arbitrary cardinality with NodeJS & TypeScript

My removeObjects function has me stummped.The function is suppose to syncronoulsy get a list of objects in an S3 bucket then asyncronously removes the objects. Repeat if the list was truncated, until the there are no more objects to remove. (AWS doesn't provide the total count of objects in the bucket and listObjects pages the results.)
What am I doing wrong / why doesn't my function work? The solution should exploit single thread and async nature of JS. For the bounty I am hoping for an answer specific to the module. The git repo is public if you want to see the entire module.
export function removeObjects(params: IS3NukeRequest): Promise<S3.Types.DeleteObjectsOutput> {
const requests: Array<Promise<S3.Types.DeleteObjectsOutput>> = [];
let isMore;
do {
listObjectsSync(params)
.then((objectList: S3.Types.ListObjectsV2Output) => {
isMore = objectList.ContinuationToken = objectList.IsTruncated ? objectList.NextContinuationToken : null;
requests.push(params.Client.deleteObjects(listObjectsV2Output2deleteObjectsRequest(objectList)).promise());
})
.catch((err: Error) => { Promise.reject(err); });
} while (isMore);
return Promise.all(requests);
}
export async function listObjectsSync(params: IS3NukeRequest): Promise<S3.Types.ListObjectsV2Output> {
try {
return await params.Client.listObjectsV2(s3nukeRequest2listObjectsRequest(params)).promise();
} catch (err) {
return Promise.reject(err);
}
}
Thanks.
The thing is that listObjectsSync function returns a Promise, so you need to treat it as an async function and can't just use a loop with it. What you need to do is to create a chain of promises while your isMore is true, I've done it using a recursive approach (I'm not pro in TS, so please check the code before using it). I also haven't tried the code live, but logically it should work :)
const requests: Array<Promise<S3.Types.DeleteObjectsOutput>> = [];
function recursive(recursiveParams) {
return listObjectsSync(recursiveParams).then((objectList: S3.Types.ListObjectsV2Output) => {
let isMore = objectList.ContinuationToken = objectList.IsTruncated ? objectList.NextContinuationToken : null;
requests.push(params.Client.deleteObjects(listObjectsV2Output2deleteObjectsRequest(objectList)).promise());
if (isMore) {
//do we need to change params here?
return recursive(recursiveParams)
}
//this is not necessary, just to indicate that we get out of the loop
return true;
});
}
return recursive(params).then(() => {
//we will have all requests here
return Promise.all(requests);
});

Resources