Not able to call http post method - javascript

I am new to javascript world. httpService.post is never executed. How can I achieve this?
async createInboundRequest_1(payload: InboundRequestDto) {
console.log("Request Dto ");
console.log(payload);
return this.fetchLookupReferenceData(payload).then(res => {
console.log("Final Response ");
console.log(res);
this.httpService.post(this.api_url, res).pipe(
map(res_1 => res_1.data),
)
});
}

One of my colleagues suggested to change the above code as given below and it worked but I am still not sure why this works.
async createInboundRequest_1(payload: InboundRequestDto) {
const enrichedRequest = await this.fetchLookupReferenceData(payload);
const res = this.httpService.post(this.api_url, enrichedRequest).subscribe(res_1 => {
return res_1.data;
})
}

Related

How to use async await with subscribe angular

I'm calling createOtherKind() function and trying to use the value of this.listKinds. My problem is that isKindOtherCreated is not waiting this.getKinds() to finish and this.listKinds is undefined.
How can i do it?
Code:
getKinds(): void {
this.detailsService.getKinds().subscribe(async response =>{
this.listKinds = await response.body;
})
}
async createOtherKind() {
await this.getKinds();
const isKindOtherCreated = this.listKinds.find(kind => kind.name === "Other");
if(!isKindOtherCreated) {
this.createdKind.name = "Other";
this.createKind();
}
}
You can call the createOtherKind() method inside getKinds() method. This is how you will get the value from this.listKinds variable. subscribe is async method. So, it does not wait for the reponse.
Here is Example:
getKinds(): void {
this.detailsService.getKinds().subscribe(async response =>{
this.listKinds = response.body;
await this.createOtherKind();
})
}
async createOtherKind() {
const isKindOtherCreated = this.listKinds.find(kind => kind.name === "Other");
if(!isKindOtherCreated) {
this.createdKind.name = "Other";
this.createKind();
}
}
The issue is happening because you're mixing Observables (where you have subscribe) with async/await. If you want to stick to using promises you could revise your getKinds function to something like this:
getKinds(): void {
// Convert your observable to a Promise so you can use `await` on it
return this.detailsService.getKinds().toPromise().then((response) => {
this.listKinds = await response.body;
});
}
For more details, I recommend taking a look at this similar question.
You use subscribe here, so I guess this.detailsService.getKinds() returns an observable. You can make things with it then return it to be able to subscribe something else in another part of your code. like:
getKinds(): Observable<any> {
let myObs = this.detailsService.getKinds(); //Getting your observable
//Reading result
myObs.subscribe(response => {
this.listKinds = response.body;
});
//Returning it to use it somewhere else
return myObs;
}
createOtherKind() {
//Make request and subscribe to observable
this.getKinds().subscribe( res => {
const isKindOtherCreated = this.listKinds.find(kind => kind.name === "Other");
if(!isKindOtherCreated) {
this.createdKind.name = "Other";
this.createKind();
}
}
}
EDIT
As said by Andres2142, subscribe twice isn't exactly the right way to act. It should work but the result isn't perfectly stable, the best way is to replace the first subscribe by a tap pipe since it is desinged to perform side-effects. So a better answer is:
getKinds(): Observable<any> {
return this.detailsService.getKinds()
.pipe(
tap( (response) => {
this.listKinds = response.body;
})
);
}
// createOtherKind() Doesn't need to change

Mongoose Object.save() only working if called twice

I know this sounds rediculess...
In my function index() I retrieve a Model for a specific collectionName promted by commandline parameters. After a async AXIOS API call a saveToDB(response, model) is called.
export async function index(collectionName) {
let model = getModelForCollection(collectionName)
await axios.get(url)
.then(resp => {
saveToDB(resp.data, model)
.then(saved => {
...
})
})
}
async function saveToDB(response, model) {
const word = new model({response})
await word.save()
.then(() => {
console.log("saved")
})
}
So basicly this should easily work, but the strange thing is. This does only! work, if I save another document prior to calling saveToDB() in index(). Changing the function to;
export async function index(collectionName) {
let model = getModelForCollection(collectionName)
let word = new model({word: 'WORT'})
await word.save().then(() => {
console.log("saved")
})
await axios.get(url)
.then(resp => {
saveToDB(resp.data, model)
.then(saved => {
...
})
})
}
Is there anything strange going on I am not aware of? Excuse my super unspecific question.
Maybe you should read the docu: https://mongoosejs.com/
or search for related questions. I guess its not a mongoos problem.
Why are you consuming and "awaiting" the Promises at the same time. Why don't you keep it simple like this:
export async function index(collectionName) {
try {
let model = getModelForCollection(collectionName)
let resp = await axios.get(url);
let saved = await saveToDB(resp.data, model);
} catch (error) {
console.log("Error");
console.log(error);
}
}
async function saveToDB(response, model) {
try {
const word = new model({ response });
let writeStatus = await word.save();
console.log("saved");
} catch (error) {
console.log("Error");
console.log(error);
}
}

Chaining unknown number promises in a recursive function

I'm trying to find the best way to go about this service call where I retain all the data in a single object. The call returns an object that has a property of next_page_url. If there is a next_page_url the function should keep chaining. Since I don't know what the url is until the next call resolves I need to call these in order and resolve them in order. I'm also collecting data from each call. I haven't been able to figure out what the structure should be
what I have so far
getDataFromAllPages = (url) => {
waniKaniAxios.get(url).then(object => {
if(object.data.pages.next_url){
return this.getDataFromAllPages(object.data.pages.next_url.replace(waniKaniAxios.defaults.baseURL, ''));
}
});
}
getWanikaniData = () => {
this.getDataFromAllPages('/subjects?types=vocabulary').then(result => {
console.log(result);
});
}
Abstract away the wanikaniaxios.get in another function to make recursion clearer.
Here's my badly formatted code (don't know how SF editor works) , feel to ask any questions if you have any. Happy coding.
getWanikaniData = () => {
this.getDataFromAllPages("/subjects?types=vocabulary")
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err); // always put a .catch when you're using prmomises.
});
};
getDataFromAllPages = async (url) => {
// using async await;
try {
let arr = []; // i am assuming you'll improve upon what data structure you might want to return. Linked list seems best to me.
const object = await waniKaniAxios.get(url);
if (object.data.pages.next_url) {
const laterData = await this.getDataFromAllPages(
object.data.pages.next_url.replace(waniKaniAxios.defaults.baseURL, "")
);
arr = [...arr, ...laterData];
} else {
arr = [...arr, object];
}
Promise.resolve(arr);
} catch (err) {
Promise.reject(new Error(`Oops new wanikani error, ${err}`));
}
};
FINAL UPDATE
Using part of the answer below I managed to get it working. Had to partially give up on the recursion aspect because I didn't how to make the promise resolve into data
Here's the final solution that I came up with
getDataFromAllPages = async (url) => {
let results = {};
try {
//getting intial data
const initialData = await waniKaniAxios.get(url);
//using the intial data and mapping out the levels then saving it into results object
results = this.mapOutLevels(initialData.data, results);
//get the next page url
let nextPageUrl = initialData.data.pages.next_url;
//while there is a next page url keep calling the service and adding it to the results object
while (nextPageUrl) {
const laterData = await waniKaniAxios.get(nextPageUrl);
nextPageUrl = laterData.data.pages.next_url;
results = this.mapOutLevels(laterData.data, results);
}
} catch (err) {
Promise.reject(new Error(`Opps new wanikani error, ${err}`));
}
return Promise.resolve(results);
};
getWanikaniData = () => {
this.getDataFromAllPages("/subjects?types=vocabulary")
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err);
});
};

Javascript Async/Await not returning, more like Await_Forever

I started started a node environment based off express, my issue is more with Promise.
I've written a module that has an http call (axios) and i'm using async/await in order to receive the response and handle it, everything is working great in the module in terms of flow and i'm able to execute console.log()s, yet my returned value isn't coming back to index.js.
index.js
works great and my readFile() function works great.
const getDistance = require('./actions/getDistance');
app.post('/find-closest', async (req, res) =>{
try{
let address = req.body.address;
let data = await readFile('src/agents.json');
return res.json(getDistance(JSON.parse(data),address));
} catch (e) {
console.log('Error');
console.log(e);
return res.json(e);
}
});
getDistance.js
module.exports = function (agents, origins) {
let destinations = '&destinations=' + agents.map(agent => agent.address).join('|');
const getDistances = async () => {
try {
return await axios.get(url + origins + destinations + apiKey)
} catch (error) {
console.error(error)
}
};
const setDistancesResponse = async () => {
const distances = await getDistances()
console.log('test',distances.data); //<=this returns
return 'baboom'; //this is not returned through
};
setDistancesResponse();
};
I am expecting my endpoint to return a JSON response of the string "baboom".
What am I doing wrong here?
Thanks, Bud
Your exported getDistance function doesn't return anything. You are probably looking for
module.exports = async function(agents, origins) {
const destinations = '&destinations=' + agents.map(agent => agent.address).join('|');
const distances = await axios.get(url + origins + destinations + apiKey)
console.log('test',distances.data); // this logs something
return 'baboom';
};
and given that this now returns a promise, you will have to wait for the result value:
app.post('/find-closest', async (req, res) =>{
try{
let address = req.body.address;
let data = await readFile('src/agents.json');
return res.json(await getDistance(JSON.parse(data), address));
// ^^^^^
} catch (e) {
console.error('Error', e);
return res.json(e);
}
});
I think you misses return value. Try this:
return setDistancesResponse();

JavaScript function(callback).then(), callback executes after then

I have trouble to get this to work.
I have a function getItem:
export const getItem = async (key, callback) => {
value = await Expo.SecureStore.getItemAsync(key).catch((error) => console.log(error));
callback(value);
}
getItem is supposd to get a token and pass that token to the callback.
Now I want to use getItem in this (simplified) class:
export class Post {
constructor(){
this.token = false;
}
post() {
console.log('Token: ' + this.token);
...
}
setToken(token){
console.log('Set token.');
this.token = token;
}
authorizedPost() {
getItem('token', this.setToken.bind(this)).then(
this.post()
);
}
}
I use this class like this:
let post = new Post();
post.authorizedPost();
This is the output I get:
Token: false
Set token.
But I need the token to be set and after that, I want to call the method this.post();
Since I'm a beginner, I want to excuse if that issue is trivial. But I am thankful for every help!
I had to pass a function to then like this:
authorizedPost() {
getItem('token', this.setToken.bind(this)).then(
()=>this.post()
);
}
I know you didn't really ask, but…
Part of the reason the code is difficult to debug is because you are using callbacks when you don't need to and mixing them with promises. These are two different async paradigms that are normally better off separate. You can get rid of the callback in your code in a way that will make it much more readable.
Expo.SecureStore.getItemAsync()
returns a promise, so just return it.
const getItem = (key) => Expo.SecureStore.getItemAsync(key);
Then in your method you can call then and simply call the function you were passing as a callback. No need for callback or bind. Just one line after the other:
authorizedPost() {
getItem('token').then(val => {
this.setToken(val) // the order is now obvious
this.post()
})
.catch((error) => console.log(error))
}
Here's a snippet with a faked Expo method:
let Expo = {
SecureStore: {
getItemAsync() {
return new Promise((resolve, reject) => setTimeout(() => resolve("someFancyToken"), 1000))
}
}
}
class Post {
constructor() {
this.token = false;
}
post() {
console.log('Token: ' + this.token);
}
setToken(token) {
console.log('Set token.');
this.token = token;
}
authorizedPost() {
getItem('token').then(val => {
this.setToken(val)
this.post()
})
.catch((error) => console.log(error))
}
}
const getItem = (key) => Expo.SecureStore.getItemAsync(key);
let post = new Post();
post.authorizedPost();

Categories

Resources