FREE Webinar: Should I use React or Vue?

Make a Stellar React + NASA App in 10 Minutes

One of the most stellar open API's out there is the NASA Astronomy Picture of the Day. In today's article, we are going to mess around with that API and build an application that displays the photo of the day, the title of that photo, the current date, and some information about the picture.

What We Will Be Building

Using the NASA Open API: Astronomy Picture of the Day (APOD), we will be building an application that displays the information that is provided by that API. The information we will display is:

  • The photo
  • The photo's title
  • Current date
  • Information on the photo

We will be building our application with React. More specifically, we will be using the React Router and even throw in a .env file for our API key. We are going to start from a new environment, but if you would like to look at the finished code now, please visit this GitHub repo.

What is the React Router?

The react router is React's way of navigating around an application. We are able to change pages waiting having to load each page. We will build a Single Page Application (SPA) so even though it looks like we have multiple pages, we have one that is split into sections.

Those sections, or components as we like to call them, can be navigated to depending on what the URL says. The React Router has us add to the URL to specify which component we are viewing. Generally, the Home page is declared with / and if we were to add an About page, we could do something like /about.

In our app that we build, we will be using the following parts of the React Router:

  1. BrowserRouter - How we tell our browser that we are going to be setting routes
  2. Route - Matching up a component with the URL path we assign it to
  3. Link - Using those URL path's to already assigned components

NASA's Open API

Before we dive into the code, let's chat a little bit about setting up our API. If we were to head to { NASA's API } page we would find all the information about all of NASA's open APIs. Scroll down to where it says "Browse APIs" and we will see the API we want to use, "APOD: Astronomy Picture of the Day":

In this section, we will also see the example query:

React LogoReact Logo
Learn by Building
Build 20 React apps. Go beyond 'hello world'
https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY

We will be using this. Where it says DEMO_KEY, we will need to replace that with our own API key. Let's go grab that!

API Key

On the same page, we are going to scroll up to the section that says, "Generate API Key". We can also click on "Generate API Key" in the nav bar at the top:

Fill in the required information. No need to do the "Application URL".

Once we have done that, we will receive an email with an API Key in that email. Hold onto that key.

Nasa API Information

So far we need the following things for our NASA API connection:

  1. The following URL: https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY
  2. Our individual API Key that was sent to our email.

Creating the React App

Now that we have all the information we will need to connect our application to the open NASA open API, let's start building out our application!

For today's example, we will be using the Terminal to run commands to get our application set up, get our application running, and add in dependencies. Open up the Terminal and navigate to the folder we would like our application to live.

Once there, we are going to be using the create-react-app command to get our application running. Run the following command:

npx create-react-app nasa-apod

The npx command will install and run the command create-react-app for us. The last part of that command is the name of our app. We are going to be naming our app nasa-apod, feel free to name it whatever.

Once our app is created, we are going to run the following command to get into our project:

cd nasa-apo

Open up the project in whichever text editor, for example, VS Code.

And to get our app running, we are going to run the command:

npm start

And head on over to localhost:3000 in any browser to see our default React start page.

Yay! Our React app is ready for us!

Our Components

Quickly, let's set up our components that will hold our code. Within the /src folder, create a folder named /components. With that folder, create three files:

  1. /Home.js
  2. /NasaPhoto.js
  3. /NavBar.js

Let's start building!

React Router Magic!

Before we start building out each component, let's set up our App.js so that our app can have seamless routing. We will need to install the dependency. To do so, run the command:

npm install --save react-router-dom

Navigate to src/App.js and replace all the code in there with the following code:

// src/App.js

import React from "react";
import { BrowserRouter, Route } from "react-router-dom";
import Home from "./components/Home";
import NasaPhoto from "./components/NasaPhoto";
import "./App.css";

export default function App() {
  return (
    <BrowserRouter>
      <div className="app">
          <Route component={Home} path="/" exact />
          <Route component={NasaPhoto} path="/nasaphoto" />
      </div>
    </BrowserRouter>
  );
}

In here we see that we have imported the react-router-dom, our /Home and /NasaPhoto components, and set up the routing for that.

For the react-router-dom dependency, we pulled out BrowserRouter and Route for our routing.

  • BrowserRouter will wrap around our declared routes.
  • Route will help us build out our routes, what component the route will show, and how the URL route will look.

We can give BrowserRouter an alias if we want. That would look like `{ BrowserRouter as Router }` in the import.

We will be getting an error right now in our localhost:3000 view! That's because we haven't put anything into our components. Let's work on those!

Home Component

Our Home component is going to have a large clickable button that will take us to the other component that will display the NASA picture of the day.

Head to src/components/Home and add the following code:

// src/components/Home.js

import React from "react";
import { Link } from "react-router-dom";

export default function Home() {

  return (
    <div className="home">
      <Link className="home-link" to="/nasaphoto" >See into the stars!</Link>
    </div>
  );
}

Remember how in App.js we assigned the route, /nasaphoto to the component, NasaPhoto? We are now using that assignment in this component. We don't need to tell the <Link> which component because that's already done!

If we visit our browser at localhost:3000, we will see the words "See into the stars!" and nothing else. We may need to restart our server.

NASA APOD Component

Let's have that /nasaphoto URL route show us something! And speaking of the NASA Photo, let's call our API!

Navigate to our src/components/NasaPhoto.js file and paste in the following code:

// src/components/NasaPhoto.js

import React, { useState, useEffect } from "react";

export default function NasaPhoto() {
  const [photoData, setPhotoData] = useState(null);

  useEffect(() => {
    fetchPhoto();

    async function fetchPhoto() {
      const res = await fetch(
                // we'll update the KEYHERE soon!
        `https://api.nasa.gov/planetary/apod?api_key=KEYHERE`
      );
      const data = await res.json();
      setPhotoData(data);
    }
  }, []);

  if (!photoData) return <div />;

  return (
    <div className="nasa-photo">
        <img
          src={photoData.url}
          alt={photoData.title}
          className="photo"
        />
      <div>
        <h1>{photoData.title}</h1>
        <p className="date">{photoData.date}</p>
        <p className="explanation">{photoData.explanation}</p>
      </div>
    </div>
  );
}

Let's walk through this code!

We are using React Hooks so we see that for state, we have set it to null and later we set setPhotoData to the data we pull out of the API.

In the return() we are using photoData to use each element of the API in an organized way. We are using:

  1. Photo URL - That is the photo itself.
  2. Photo Title - That will be used as our alt for the photo and the h1 on our page.
  3. Photo Date - This will be the current date because this API is the Astronomy Picture of the Day.
  4. Photo Explanation - This will be a paragraph of information that NASA provides about the photo.

Handling the Media Type

The API sometimes sends back a short video. So we want to be able to display that properly. If the media type is "image", we will return it as an image. If not, we will return the "image/video" in an <iframe />.

Update the <img> tag to look like this. We're using a JavaScript ternary operator to either show an image or a video.

{photoData.media_type === "image" ? (
  <img
    src={photoData.url}
    alt={photoData.title}
    className="photo"
  />
) : (
  <iframe
    title="space-video"
    src={photoData.url}
    frameBorder="0"
    gesture="media"
    allow="encrypted-media"
    allowFullScreen
    className="photo"
  />
)}

Adding an API Key

If we look at this part of the component:

const res = await fetch(
    // we'll update the KEYHERE soon!
  `https://api.nasa.gov/planetary/apod?api_key=KEYHERE`
);

We can see the KEYHERE part of the fetch. We don't want our key pushed to any source control, in our case, GitHub. So let's go ahead and create a secure way to store our key!

Environment Variables

Remember earlier we generated an API key on the NASA API website? That should have been sent to our email address that we put in the form. Let's go grab that key!

In the source of our project, let's create a file called .env. In this file, put in the following information:

// .env

REACT_APP_NASA_KEY="YOUR KEY HERE"

Where it says, "YOUR KEY HERE" put your unique key that was emailed to you. Go to the .gitignore file and put .env in there. That way, when this is pushed to GitHub, it doesn't push that sensitive key.

Using Our Key

Let's head back to our src/components/NasaPhoto.js file and update it so it uses our key. At the top of the file, below the imports, add the following line:

const apiKey = process.env.REACT_APP_NASA_KEY;

React uses REACT_APP_ to know that it's using an environment variable. That is why we named our key, REACT_APP_NASA_KEY. That makes it so we don't have to import the .env file, it just knows!

Further down in the file, update the following code:

const res = await fetch(
    // this https was updated with ${apiKey}
  `https://api.nasa.gov/planetary/apod?api_key=${apiKey}`
);

We are now pulling in the NASA APOD API. Let's go ahead and restart our server and head to localhost:3000. We should see something like this!

The view will be different depending on the day!

NavBar Component

Before we throw on styling for our two components, let's add a navigation bar to our NasaPhoto view. Navigate to our src/components/NavBar.js file. Paste in the following code:

// src/components/NavBar.js

import React from 'react';
import { Link } from 'react-router-dom';

export default function NavBar() {
    return (
        <div className="navbar">
            <ul>
                <Link className="link" to="/" exact >Take Me Home</Link>
            </ul>
        </div>
    )
}

In here, we are creating a nav bar that will take the user back to the home page where it says, "See into the stars!"

But before this can show up, we will need to nest this component inside another one. We want it on the /nasaphoto route, so let's head to our src/components/NasaPhoto.js. We want the following line to be added to our import at the top of the file:

import NavBar from "./NavBar";

Next, we want to use that import. In the return of the file, add above the first <div>:

<NavBar />

Things will break. 😳Let's chat about that real quick.

React Fragments

In React, we may want to return multiple elements. Rather than wrapping elements in a <div> we can wrap it in a Fragment. That will look like this:

return (
    <React.Fragment>
      <ChildA />
      <ChildB />
    </React.Fragment>
  );

And the short syntax version of this looks like:

return (
    <>
      <ChildA />
      <ChildB />
    </>
  );

We are going to be using the short syntax way. Let's add that in our return() in the NasaPhoto.js file.

Final NasaPhoto File

After it's all said and done, let's look at our final product of the src/components/NasaPhoto.js file:

// src/components/NasaPhoto.js

import React, { useState, useEffect } from "react";
import NavBar from "./NavBar";

const apiKey = process.env.REACT_APP_NASA_KEY;

export default function NasaPhoto() {
  const [photoData, setPhotoData] = useState(null);

  useEffect(() => {
    fetchPhoto();

    async function fetchPhoto() {
      const res = await fetch(
        `https://api.nasa.gov/planetary/apod?api_key=${apiKey}`
      );
      const data = await res.json();
      setPhotoData(data);
      console.log(data);
    }
  }, []);

  if (!photoData) return <div />;

  return (
    <>
    <NavBar />
    <div className="nasa-photo">
      {photoData.media_type === "image" ? (
        <img
          src={photoData.url}
          alt={photoData.title}
          className="photo"
        />
      ) : (
        <iframe
          title="space-video"
          src={photoData.url}
          frameBorder="0"
          gesture="media"
          allow="encrypted-media"
          allowFullScreen
          className="photo"
        />
      )}
      <div>
        <h1>{photoData.title}</h1>
        <p className="date">{photoData.date}</p>
        <p className="explanation">{photoData.explanation}</p>
      </div>
    </div>
    </>
  );
}

We should also see our navigation bar at the top of the route, /nasaphoto. If we click on "Take Me Home" it should take us back to the / route.

Styling Our Components

We are not going to go much into the styling of our components, but let's make our application look nice! We're bringing in a Google Font called Righteous. Feel free to choose your own if you want to switch it!

Head to the App.css file and replace all the styling in there with this:

// src/App.css

@import url('https://fonts.googleapis.com/css2?family=Righteous&display=swap');

body {
  font-family: 'Righteous', cursive;
  color: #d14f4f;
  line-height: 1.7;
  font-size: 19px;
  background-color: #222222;
  background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23424242' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}

/_ navbar ---------- _/

.navbar {
  background-color: rgba(22, 22, 22, 0.8);
  display: flex;
  justify-content: center;
}

.link {
  color: #efefef;
  display: inline-block;
  padding: 3px 20px;
  font-size: 16px;
  text-decoration: none;
  transition: 0.3s ease all;
}

.link:hover {
  color: #f59494;
  transform: scale(1.1);
}

/_ nasa photo ---------- _/

.nasa-photo {
  display: flex;
  padding: 40px;
  margin: 0 auto;
  max-height: 100%;
}

.nasa-photo img {
  width: 50%;
  margin-right: 50px;
  object-fit: contain;
  max-height: 80vh;
}

.nasa-photo h1 {
  margin-top: 0;
  margin-bottom: 0;
}

.nasa-photo .date {
  margin-top: 0;
  margin-bottom: 30px;
}

.nasa-photo .explanation {
  color: #bbb;
}

@media (max-width: 1280px) {
  .nasa-photo {
    display: block;
  }

  .nasa-photo img {
    width: 100%;
    margin-right: 0;
    margin-bottom: 30px;
  }
}

.home {
  display: flex;
  height: 100vh;
  align-items: center;
  justify-content: center;
}

.home-link {
  font-size: 40px;
  background: #f59494;
  display: inline-block;
  padding: 40px 80px;
  color: #fff;
  border-radius: 50%;
  text-decoration: none;
  transition: 0.3s ease all;
  text-transform: uppercase;
}

.home-link:hover {
  border-radius: 5px;
  background: #e77171;
}

In our file, we have styled each component. Feel free to change colors, fonts, anything really to make it more your own!

Our Finished App!

We may need to restart the server. If so, do that and return to localhost:3000. We should see the following view:

If we were to click on the giant button in the middle, we would be routed to this view:

Conclusion

The NASA APOD API is a fun one because it changes every single day. It would be fun to add this API to a project where you know visitors would like to see that updated image every time they view your website.

Using React Routing, React Fragments, and even environment variables, we were able to build a pretty application with some stellar data from an API. Mess around with the styling, add this API call to an existing application, or just be happy with this app! We built something pretty cool together!

Like this article? Follow @kapehe_ok on Twitter