-1

I am writing weather application in JavaScript and as you can guess there are lots of API requests. So here I make a request to API which then will return me image of the city. City is coming from user input.

async getCityImage(city) {
    console.log(city, 'getCityImage');
    await fetch(`https://api.teleport.org/api/urban_areas/slug:${city}/images/`)
      .then(res => res.json())
      .then((res) => {
        this.imageUrl = res.photos[0].image.mobile;
      });
  }
}

The problem is that user input may be inappropriate and of course API would return an error like this

> GET https://api.teleport.org/api/urban_areas/slug:munchen/images/ 404

(Not Found)

For example there are some cities which names are separated by hyphen 

cansas-city, guatemala-city etc...

So I would like to handle errors so that error doesn't affect to UI, but make another request like this and then return the answer `

GET https://api.teleport.org/api/urban_areas/slug:${city}-city/images/

I have tried to make it happen with nesting requests inside then, but it doesn't work

Luca Kiebel
  • 9,790
  • 7
  • 29
  • 44
Norayr Ghukasyan
  • 1,298
  • 1
  • 14
  • 28

4 Answers4

0

you can use something like this

async getCityImage(city) {
    console.log(city, 'getCityImage');
    await fetch(`https://api.teleport.org/api/urban_areas/slug:${city}/images/`)
      .then(res => res.json())
      .then((res) => {
        this.imageUrl = res.photos[0].image.mobile;
      })
      .catch((e) => { //do something with error});
  }
}
Rohit Choudhary
  • 2,253
  • 1
  • 23
  • 34
0

You could use a try catch statement like this:

async getCityImage(city) {
  let res;
  try {
    res = await fetch(`https://api.teleport.org/api/urban_areas/slug:${city}/images/`); 
    return res.photos[0].image.mobile;
  } catch(e) {
    // here you can do something when the request fails
    res = await trySomethingElse();
    return res
  }
}
tallpaulk
  • 164
  • 1
  • 1
  • 11
0

You can do something like this -

Native fetch API - UPDATED

(async () => {

    async function getCityImage(city) {
        let response = await fetch(`https://api.teleport.org/api/urban_areas/slug:${city}/images/`);
        if (response && response.status && response.status === 200) {
            const json = await response.json();
            return json.photos[0].image.mobile;
        } else {
            throw Error(`got error, error code - ${response.status}`);
        }
    }

    try {
        console.log(await getCityImage("london"));
        console.log(await getCityImage(null));
    } catch (error) {
        console.error(error);
    }

})();
planet_hunter
  • 3,866
  • 1
  • 26
  • 39
  • Are you using `fetch node module` to get data from a url? If you already have it, can you share that code as well? – planet_hunter Sep 12 '18 at 17:18
  • Check the updated answer. This will catch all the network errors. – planet_hunter Sep 12 '18 at 17:32
  • without async/await it doesn't even return the image for appropriate city – Norayr Ghukasyan Sep 12 '18 at 17:36
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Sep 12 '18 at 17:59
  • @NorayrGhukasyan I was just trying to explain that we need to handle the response and return a custom promise that handles http error codes (async/await is not an actual problem here). I have updated the answer anyway to make use of async/awaits – planet_hunter Sep 12 '18 at 18:45
  • @Bergi Thanks for pointing out the wrong promise usage. I have updated the asnwer to use `Promise.resolve` & `Promise.reject` APIs now. I am not sure if this will solve the problem though! Please let me know if I am still doing it in a wrong way! :) – planet_hunter Sep 12 '18 at 18:51
  • Yes i improve my code . You are right about Promise constructor antipattern . I have updated my answer and that is working – Norayr Ghukasyan Sep 12 '18 at 18:58
  • 1
    @planet_hunter If you are using `async`/`await`, you should not need to use `then` at all any more. Don't mix them. Btw, inside an `async function` you can just `throw` and `return`, you don't need to use `Promise.resolve` and `Promise.reject` – Bergi Sep 12 '18 at 19:35
  • I think now I got it in a right way! Thanks a lot @Bergi :) – planet_hunter Sep 12 '18 at 19:44
0

Here is the solution for me, may be not the best but in this case it helps me .

getCityImage(city, hyphen) {
    console.log(city, 'getCityImage');
    return fetch(`https://api.teleport.org/api/urban_areas/slug:${city}/images/`)
      .then(res => res.json())
      .then((res) => {
        if (res.status === 404)
          return fetch(`https://api.teleport.org/api/urban_areas/slug:${city}-city/images/`)
            .then(res => res.json());
        else
          return res;
      })
      .then((res) => {
        this.imageUrl = res.photos[0].image.mobile;
      })
      .catch((err) => {
        console.log(err, 'erroroooooooorr');
      });
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Norayr Ghukasyan
  • 1,298
  • 1
  • 14
  • 28
  • You should've [put it in your question](https://stackoverflow.com/posts/52299873/edit) if this solution is not working. Or does it now? – Bergi Sep 12 '18 at 17:59
  • It is working . Should i now close the answer and if it is , how should i do it ? – Norayr Ghukasyan Sep 12 '18 at 18:00
  • Actually I doubt that it is working, you'd need to swap the `.then(res => res.json())` and `.then((res) => { if (res.status === 404) { …` - the parsed JSON won't have a `status` property. Also avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Sep 12 '18 at 18:03
  • `{status: 404, message: "Not Found. You have requested this URI [/api/publi…ex("slug\:[0-9a-z-]+"):urban_area_id>/salaries/ ?"} "response000"` this is the answer . Actually it it has a `status` – Norayr Ghukasyan Sep 12 '18 at 18:09
  • Take a look at this updated version . So i listened to you and decided to improve it .You were right about `Promise constrcutor antipattern` . – Norayr Ghukasyan Sep 12 '18 at 18:55
  • You'd need to put the second `.then(res => res.json())` inside the `if`. And the first `this.imageUrl = …` should be an `else return res;` – Bergi Sep 12 '18 at 19:34
  • I didnt catch your mind . Could you please edit the answer , so i could see it – Norayr Ghukasyan Sep 12 '18 at 19:38
  • 1
    Done. You might want to extract the `fetch(…).then(res => res.json())` that is used twice now into a helper function. – Bergi Sep 12 '18 at 19:43
  • nice. Thanks for helping and advice – Norayr Ghukasyan Sep 12 '18 at 19:45