NASA Photo of the Day 5

cesareferrari

Cesare Ferrari

Posted on January 7, 2020

NASA Photo of the Day 5

Fetching a photo from a remote API with Axios and Redux middleware

Now that we have our action creator set up correctly to dispatch actions using middleware, we can go about actually fetching something from the remote API.

To work with the remote API we use Axios. Axios is an http client that lets us make remote calls easily.

We first need to install it:

npm install axios

and then we import it into our action creator file:

// actions/index.js

import axios from 'axios';

Our action creator is currently only dispatching the FETCH_PHOTO_START action. Now we need it to handle a couple more actions.
One is FETCH_PHOTO_SUCCESS. This action will be dispatched if our Axios call is successful.
The second action to handle is FETCH_PHOTO_FAILURE that will be dispatched if the Axios call resolves with an error.
Let's set up our Axios connection inside the action creator:

// src/actions/index.js

export const getPhoto = () => ( dispatch ) => {
  dispatch({type: FETCH_PHOTO_START});

  axios.get('https://api.nasa.gov/planetary/apod?api_key=<---API key --->')
    .then(res => dispatch({ type: FETCH_PHOTO_SUCCESS, payload: res.data }))
    .catch(err => dispatch({ type: FETCH_PHOTO_FAILURE, payload: err }))
}

We invoke the axios.get() method passing the URL to the NASA API, including the API key that we have received from NASA when we signed up for API access.
If we get a successful response, we dispatch FETCH_PHOTO_SUCCESS with a payload of the response data.
If we get an error, we dispatch FETCH_PHOTO_FAILURE and we send the error along as a payload, so we can see what the actual error was.

We also need to define the new constants at the top of the file:

// src/actions/index.js

export const FETCH_PHOTO_SUCCESS = 'FETCH_PHOTO_SUCCESS'
export const FETCH_PHOTO_FAILURE = 'FETCH_PHOTO_FAILURE'

Now that our action creator is all set, we need to handle the dispatched actions in the reducer.
We first import the new action type constants:

// src/reducers/index.js

import { FETCH_PHOTO_START,
         FETCH_PHOTO_SUCCESS,
         FETCH_PHOTO_FAILURE }
from '../actions';

Then we add two more case statements to handle success and error:

// src/reducers/index.js

const reducer = (state = initialState, action) => {
  switch (action.type) {

    case FETCH_PHOTO_START: {
      return {
        ...state,
        isLoading: true
      }
    }

    case FETCH_PHOTO_SUCCESS: {
      return {
        ...state,
        photoOfTheDay: action.payload,
        isLoading: false
      }
    }

    case FETCH_PHOTO_FAILURE: {
      console.log("FAILURE PAYLOAD:", action.payload)  // for testing
      return {
        ...state,
        isLoading: false
      }
    }

    default: return state;
  }
}

With these changes our photo should be retrieved correctly, but there is still a little issue to fix.
In our NASAPhoto component, we display the photo in this way:

<img src={props.photoOfTheDay} alt="NASA pic" />

This won't show a photo because after the API call photoOfTheDay is set to the full API response. Within this response, the photo URL is available at photoOfTheDay.url
We may be tempted to fix this by adding .url at the end, like this:

<img src={props.photoOfTheDay.url} alt="NASA pic" />

This would display the photo, but the problem now is that initially we display NASAPhoto component before we even perform the Axios call.
At that point photoOfTheDay is set to null and if we call .url on a null object, we get an error that breaks our application.

There are several ways to address this issue, but we are going with the simplest way, that is: check if photoOfTheDay is not null, and in this case, call .url on it and display the photo.

This is the code to achieve this:

// src/components/NASAPhoto.js

{
  props.photoOfTheDay && (
    <img src={props.photoOfTheDay.url} alt="NASA pic" />
  )
}

And with this change, we can finally retrieve and display the NASA Photo of the day.


Previous articles in this series:

  1. NASA Photo of the Day 1
  2. NASA Photo of the Day 2
  3. NASA Photo of the Day 3
  4. NASA Photo of the Day 4

I write daily about web development. If you like this article, feel free to share it with your friends and colleagues.

You can receive articles like this in your inbox by subscribing to my newsletter.

💖 💪 🙅 🚩
cesareferrari
Cesare Ferrari

Posted on January 7, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related