Handling Fetch errors

Handling Fetch errors

Question: Everything is working PERFECTLY FINE in my code, but I have DELIBERATELY inserted an error - by removing an 's' from 'meals' in the url in fetch( ) - just to check how the program will handle the error.

1) If I remove '.json' from the url, I get the red error message 'Failed to fetch'.

2) If I write '.jsonx' I get the red error message 'Something went wrong!'.

So the code handles these errors very well. But . . .

3) If I write ' . . . /meal.json' rather than ' . . . /meals.json' I do NOT get an error message.

How would you handle this type of error ?

Answer:

Unless there is a better solution, you can do this:

After: const responseData = await response.json();

Place this:

if (responseData === null) {
  throw new Error('Check your URL');
}

The response.status of your bad URL is 200 (successful).

So, you may need to be creative.

import classes from './AvailableMeals.module.css'
import Card from '../UI/Card';
import MealItem from './MealItem/MealItem';
import React, { useEffect, useState } from 'react'


const AvailableMeals = () => {
    const [meals, setMeals] = useState([]);
    const [isLoading, setIsLoading] = useState(true);
    const [httpError, setHttpError] = useState();



    useEffect(() => {
        const fetchMeals = async () => {
            const response = await fetch("https://reactfooddata-default-rtdb.firebaseio.com/meals.json");


            console.log("here");

            if (!response.ok) {
                //this is a constructor
                throw new Error('Something went wrong!')
            }

            const responseData = await response.json();
            if (responseData === null) {
                throw new Error('Check your URL');
            }
            const loadedMeals = [];
            for (const key in responseData) {
                loadedMeals.push({
                    id: key,
                    name: responseData[key].name,
                    description: responseData[key].description,
                    price: responseData[key].price
                });
            }

            setMeals(loadedMeals);
            setIsLoading(false);
        };



        fetchMeals().catch((error) => {
            // console.log(error);
            setIsLoading(false);
            //error object by default has a message property
            setHttpError(error.message);
        });


    }, [])



    if (isLoading) {
        return <section className={classes.MealsLoading}>
            <p>Loading...</p>
        </section>
    }

    if (httpError) {
        return <section className={classes.MealsError}>
            <p>{httpError}</p>
        </section>
    }




    const mealsList = meals.map((meal) =>
        <MealItem
            id={meal.id} // this is new! 
            key={meal.id}
            name={meal.name}
            description={meal.description}
            price={meal.price}
        />
    );




    return <section className={classes.meals}>
        <Card>
            <ul>
                {mealsList}
            </ul>
        </Card>
    </section>
}

export default AvailableMeals

After thinking about it a second time, I'm now no longer sure that an error message suggesting "Change your URL" would be the best approach in this situation, since the URL is hardcoded in this case (and it would be hardcoded in a real app as well).

Coding mistakes shouldn't throw errors (unlike problems that occur at runtime). They should be fixed when they are detected.

But trying out a url like .../foo.json was a useful suggestion, though, as it simulates what would happen (assuming the url is correct) if the meal provider didn't have any meals on offer at the moment.

So something like this might be an appropriate option:

<Card>
  {mealsList.length === 0 
    ? <p style={{textAlign: 'center'}}>Sorry, currently mo meals available</p>
    : <ul>{mealsList}</ul>
  }        
</Card>