angular2 : issue with rest api - javascript

I am trying to learn angular2 (coming from php scripts, it is quite difficult^^), using a real rest api in "Tour of Heroes".
From what I read, I thought it could be simple...
I have a working api, built with Express :
curl -XGET http://localhost:3001/heroes
[{"_id":"58185c8a8af4b512c51c0519","no":"1","name":"bahamut","__v":0,"updated_at":"2016-11-01T09:12:42.803Z"},{"_id":"58185ca78af4b512c51c051a","no":"2","name":"gatz","__v":0,"updated_at":"2016-11-01T09:13:11.063Z"},{"_id":"58185ec98af4b512c51c051b","no":"3","nam...
In hero.service.ts, I can get the data :
getHeroes(): Promise<Hero[]> { // {{{
console.log('getheroes in service');
console.log( "%o", this.http.get(this.heroesUrl).toPromise());
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => response.json().data as Hero[])
.catch(this.handleError);
} // }}}
console screenshot
When I do same console.log on original "Tour of Heroes", I have an array in data whereas here I have a string...
I guess I have to convert somewhere the string but whatever I tried, it does not work.
(I read many examples with Observable too but I have not succeeded either)
Help wanted to explain me how to...
TIA
JP

You're so close! The mistake here is in how you handle Promises, along with misunderstanding how they return. In this case you were trying to assign an undefined property (response.json().data) when you meant to coerce response.json() as type Hero[] then return.
What you'll need to do is ensure you have a matching type to assign your response when it's converted to a JSON with that json() call. The Hero type in the guide does not match your response, and you'll have errors because of that.
To check that you're receiving a response, make a call to the service's getHeroes() function and log the returned value. Logging internally to the function can be done, but that would be where understanding how Promises work in depth would help more than anything.
getHeroes(): Promise<Hero[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.then((response) => response.json() as Hero[])
.catch(this.handleError);
}
If you want to know I'm not crazy, here's the code to log internally. This should log your response no matter what type is received.
getHeroes(): Promise<Hero[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.then((response) => {
console.log(response.json());
})
.catch(this.handleError);
}
For further context into why you do these then() calls, a Promise returns asynchronously which means the result is only available after an indeterminate amount of time has passed. Any execution that must wait for the result must either happen in the then() calls or after the function returns an actual value. As JS functions run synchronously if you try to execute the following example you'll see a printout of undefined rather than a string response. This is because the console.log(r) is called immediately after the promise call, completely oblivious to the fact it hasn't actually let r be assigned a value.
getHeroes(): Promise<Hero[]> {
var r;
this.http.get(this.heroesUrl)
.toPromise()
.then((response) => r = response.json())
.catch(this.handleError);
console.log(r);
}

Related

How to get the result from a pending Promise? [[PromiseResult]] [duplicate]

This question already has answers here:
Why does .json() return a promise?
(6 answers)
Closed 11 months ago.
So my code here return a Promise and since I'm using then syntax I don't know why that happens :-??
fetch('someurltoAJsonFile.json')
.then(function(response) {
console.log(response.json());});
response.json() in node-fetch library also returns a promise, instead try
fetch('someurltoAJsonFile.json')
.then(response => response.json())
.then(data => {
console.log(data)
});
you can look up more details about it here
EDIT:
It seems that the returned response wasn't in the valid json, so for the sake of completeness here is a code for text
fetch('someurltoAJsonFile.json')
.then(response => response.text())
.then(data => {
console.log(data)
});
The function given as then parameter will be executed asynchronously (sometime in the future when your server returns a response), but then itself return Promise immediately (in synchronous way) by its definition
If you want to code looks less nested (more as synchronous code) you can use await but you must opaque whole code with async function
async function load()
{
let response = await fetch('someurltoAJsonFile.json');
let data = await response.json();
console.log(data);
}
Debating whether or not this qualifies as an answer, but I ran into a similar situation today that led me to this question even though my problem ended up being environment related.
If you are seeing promise pending and your code is correct and you spend way too much time trying to figure out why the console.log isn't showing, double check that you have "Info" turned on in chrome's dev tools. I only had warnings turned on so I wasn't seeing my console.log.
This code works and show a good way to make a fetch and get the promise without the pending problem.
Run this code in your server if you have cors problem download this extension in google chrome "Allow CORS: Access-Control-Allow-Origin"
async function invoices()
{
let response = await fetch('https://blockchain.info/latestblock?utm_medium=referral&utm_campaign=ZEEF&utm_source=https%3A%2F%2Fjson-datasets.zeef.com%2Fjdorfman');
let data = await response.json();
console.log(data);
return data;
}
invoices().then(data => {
console.log(data);
});

Issue using Axios with Scryfall API

Attempting to use axios to make a get request at the following endpoint, and I keep getting errors:
When I check it using Postman and in a browser (GET request), it returns data just fine, but otherwise I can’t get a response.
This is the call I’m using, I don’t know if it’s some sort of issue with my code or with axios itself:
axios.get(`https://api.scryfall.com/cards/named?exact=${args.name}`)
.then((res) => {
console.log(JSON.stringify(res));
})
.catch((err) => {
if (err.response) {
throw new Error(`Card with name (${name}) not found!`)
}
throw new Error(`Could not complete that query!`)
})
The argument args.name is passed as part of a GraphQL resolver, and it definitely has a value, so not sure what the deal is.
Any help would be greatly appreciated!
There are a couple of problems here.
Generally it's not a good idea to throw new errors after catching the original error. As written, your code throws an additional error because the axios Promise is thrown again instead of being dealt with inside catch - so node will complain that you didn't resolve or reject the promise.
The substantive issue is the same as the one answered here except for res - the actual error is TypeError: Converting circular structure to JSON which is caused by trying to JSON.stringify the res object:
JSON doesn't accept circular objects - objects which reference themselves. JSON.stringify() will throw an error if it comes across one of these.
The request (req) object is circular by nature - Node does that.
In this case, because you just need to log it to the console, you can use the console's native stringifying and avoid using JSON
So you can fix this by changing your code to:
axios.get(`https://api.scryfall.com/cards/named?exact=${args.name}`)
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
if (err.response) {
console.error(`Card with name (${name}) not found!`)
} else {
console.error(`Could not complete that query!`)
}
})
If you were just using console.log for testing/as an example and actually need to stringify the data to use some other way, just make sure you're stringifying the data (which is presumably what you actually want) and not the whole res object:
axios.get(`https://api.scryfall.com/cards/named?exact=${args.name}`)
.then((res) => {
let scryfallData = JSON.stringify(res.data)
doSomethingWith(scryfallData)
})

How does arrow functions behave when the body is a single line?

I wanted to know when arrow functions have a single line, the curly braces and the return keyword can be omitted, it implicitly returns whatever is there. But what if I don't want to return anything.
For example in the following code snippet, the first .then should return response.json and this is what the code does, the line is implicitly returned. But in the second .then I don't want to return the console.log but according to me it is also being implicitly returned.
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => console.log(json))
My question is have I understood this properly? And does this really matter because it won't change the results of my program? And if it does what's the way around?
But what if I don't want to return anything.
Your best bet there is to use the verbose form (with curly braces) without a return. But note that even then, calling a function always ends up with a result (even if the function doesn't return anything). That result is undefined if the function doesn't return anything.
You could (ab)use the comma operator, but I discourage you from doing so, and you need () to do it:
.then(json => (console.log(json), void 0));
..not least because it's more verbose than
.then(json => { console.log(json) });
(Of course, console.log returns undefined anyway, so... :-) )
My question is have I understood this properly?
Yes, you seem to (other than a minor quibble with the word "line", see the "Side Note" below).
And does this really matter because it won't change the results of my program? And if it does what's the way around?
It certainly doesn't matter with a function like console.log that returns undefined. If nothing is using the promise returned by that final then, then no, it doesn't matter.
FWIW, the real problems with the code in the question are:
It doesn't look for HTTP success before calling json. This is a footgun in the fetch API: It only rejects the promise on network errors, not HTTP errors.
It doesn't handle rejections.
Fixing those:
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
if (!response.ok) {
throw new Error("HTTP error " + response.status);
}
return response.json();
.then(json => console.log(json))
.catch(error => {
// Handle/report error
});
Side note:
...when the body is a single line?
Lines aren't relevant here. What's relevant is that the first non-whitespace character after the => is or isn't a {. If it is, the arrow function has a function body and explicit return is required if you want to return something other than undefined. If it isn't, the arrow function has a concise body which is a single expression, the result of which is returned from the function.
have I understood this properly?
You understood properly, everything you said is good
does this really matter because it won't change the results of my program?
it doesn't really matter, it doesn't change the result of your program, it could change it if you had a 3rd then as the value returned by the console.log would become the parameter for your 3rd then callback
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => console.log(json))
.then(value => /*value is the value returned by console.log which is undefined*/)
but you're not forced to use this value it's up to you
what's the way around?
if you don't want to get the value returned by the operation then you can add curly braces
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => {console.log(json)})
.then(value => /*still undefined because a function without return still return undefined by design of the language*/)

Trouble with axios returning promise object

I imagine it's something really simple, but I'm having some trouble getting the correct response. My code is returning the promise object, and not the value.
My axios call is something like this:
export const myFunc = async (hash: string) => {
return axios.get(`${url}/${path}?hash=hash`)
.then((response: any) => {
console.log('my response: ', response.data) // {key: value} as expected
return response.data
})
}
I call it from another file
const xy = async (c: string) => {
return myFunc(c)
}
console.log('result of xy(): ' xy('some hash')) // result of xy(): { Promise <pending> } <--- ????
If I .toString() it, because I'm annoyed (and I think I had some reason why at one point but I don't remember what that is), I get
result of xy(): [object Promise]
I've googled, I've stack overflowed, and now I'm asking the question because what I've found so far doesn't quite work.
Thanks for you help
Explicit promise syntax fixed the issue. I'm sure I was missing something really simple. Thanks much to #EmileBergeron. But we also decided that the data didn't need to be encrypted at rest, so by storing this non sensitive data in an unencrypted state, we no longer needed to make a separate rest call to un-encrypt the hash and didn't need to worry about working in an additional promise in the first place.

Usage of response in React

Can someone highlight the difference between these 2 code snippets in React?
window.fetch(url)
.then((response) => {
console.log(response.json().content);
})
and
window.fetch(url)
.then((response) => response.json())
.then((data) =>{
console.log(data.content);
})
response contains a Java object and content is one of the fields in
that object.
2nd snippet prints the correct value of content whereas 1st snippet prints undefined.
Edit: My question is not about "why response gives a Promise rather than a normal object". It is more about what are the implications of response returning a promise.
The below snippet doesn't work because response.json() returns a Promise and not a simple object which is why in the second snippet it returns a correct value as you are using .then to get the value
window.fetch(url)
.then((response) => {
console.log(response.json().content); // response.json() is not an object but a promise and hence you can't access content from it directly
})
The second snippet is equilvalent to
window.fetch(url)
.then((response) => {
response.json().then((content) => console.log(content));
})
but an be simplified to chainable promises by returning the response.json() promise from the first .then as shown in your second snippet
This is because response.json() returns promise.As it returns promise, so another then is used to catch its response. More info about promises can be found here.
While using javascript fetch you need to convert response to json using response.json(). You can skip extra step of converting response to json by using axios e.g.
axios.get(url)
.then(res => {console.log(res)})

Categories