Creating and deploying a simple React Application with AWS Amplify
By: Khan Saifullah
Tags: AWS, Weather, Front End Development, Aws Amplify, React

Let’s take a quick peek at what we are building…

Developing and deploying an application to the cloud can be cumbersome and time-consuming to setup. It may make sense to take on the DevOps work yourself to deploy and scale an application if you are working on a critical need, but what if you are working on a lite application and you want to get it up and running with as little hassle and time as possible? Enter AWS Amplify. AWS Amplify is a thorough toolset to enable you to quickly deploy your front-end and back-end applications on the cloud and manage them with a CI/CD pipeline. I am going to demonstrate how you can quickly build out a React single-page application and host it with AWS Amplify in minutes.

Building the App…

We are going to be creating a simple front-end application that queries the MetaWeather API to display weather information for a specified location.

Start by creating the base React application.

npx create-react-app weatherapp

cd weatherapp

npm start

Once you run this you should see the default startup page.

We are going to remove that and add a container for our app, a page title, and a footer. Go to App.js and paste the following code

import "./App.css"; function App() { return ( <div className="App"> <div className="AppContainer"> <div className="PageTitle">Weather App</div> </div>



<div className="Footer">Built with <a href="https://www.metaweather.com/">MetaWeather</a>

</div> </div> ); } export default App;

and in App.css the following

.AppContainer{ margin:15% auto; display:flex; flex-direction: column; width: 300px; } .PageTitle{ text-align: center; font-size:40px; } .Footer{ text-align:center; font-size:15px; }

You should see something like this…

Let’s start working on adding the search functionality. You are going to want to create a bunch of folders and files (if you are not using the code from the GitHub posted down below), like this

The way the MetaWeather API works is you need to search for a location first, and then get its Where On Earth ID (woeid) to get weather information.

To get the locations, you need to query

Which will give you something like this

Since this is an array of results, we want to display all of them in a dropdown to allow a user to pick their specific location. Once you’ve picked a location you can use the woeid to get the weather info like this.

*Note, in the app I’ve replaced the hostname with a proxy set up by this user https://github.com/thebuilder/meta-weather-proxy. This is because the API by default does not accept cross-origin requests.

We are interested in the consolidated_weather array, which contains weather for a bunch of days. We want the first one since it seems it is always the present day.

the_temp contains the temperature, weather_state_name is a general description for the weather, and weather_state_abbr contains abbreviations that can be used to link to a weather icon. We will be using these in our app.

So, in LocationSearch.js we are adding the code to display an input to allow the user to search, and a dropdown to show the search results. The component contains callbacks to our parent component which handles things like a Boolean to show the dropdown or not, or the currently selected location.

import "./LocationSearch.css"; import Dropdown from "../Dropdown/Dropdown";

const LocationSearch = (props) => { return ( <div className="LocationSearchContainer"> <input type="text" placeholder="Search for a location" onChange={props.onChangeHandler} ></input> {props.showDropdown && ( <Dropdown searchResults={props.searchResults} onClickHandler={props.onClickHandler} /> )} </div> ); }; export default LocationSearch;

and its matching css code in LocationSearch.css

.LocationSearchContainer{ display:flex; flex-direction: column; position: relative; margin-top:10px; }

But you will also need the dropdown component for the code to compile

Dropdown.js

import "./Dropdown.css"; const Dropdown = (props) => { return ( <div className="DropdownContainer"> {props.searchResults.map((result, i) => ( <div key={i} onClick={() => props.onClickHandler(result.woeid)}> {result.title} </div> ))} </div> ); }; export default Dropdown;

Dropdown.css

.DropdownContainer{ position: absolute; background-color: white; margin-top:21px; max-height: 100px; width:99.2%; overflow-y: scroll; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; } .WeatherInfo{ width:70% } .WeatherIcon{ width: 25% } .WeatherIcon > img { width: 100%; margin-top:25%; } .Title{ font-size: 40px; } .Temperature, .Description{ font-size: 20px; }

As well as the handler codes to handle when you search by inputting into the form and to handle when you click on a location. You will add it to App.js like this

import "./App.css"; import { useState } from "react"; import LocationSearch from "./components/LocationSearch/LocationSearch"; function App() { const [searchResults, setSearchResults] = useState([]); const [showDropdown, setShowDropdown] = useState(false); const [locationWeather, setLocationWeather] = useState(null); const onChangeHandler = (evt) => { let locationSearchValue = evt.target.value; if (locationSearchValue === "") { setShowDropdown(false); setSearchResults([]); return; } let locationSearchQuery = `https://www.metaweather.com/api/location/search/?query=${locationSearchValue}`; fetch(locationSearchQuery) .then((res) => res.json()) .then((result) => { if (result.length > 0) { setShowDropdown(true); setSearchResults(result); } }); }; const onClickHandler = (id) => { let locationWeatherQuery = `https://www.metaweather.com/api/location/${id}/`; fetch(locationWeatherQuery) .then((res) => res.json()) .then((result) => { if (result.consolidated_weather.length > 0) { setLocationWeather({ ...result.consolidated_weather[0], title: result.title, }); } }); setShowDropdown(false); }; return ( <div className="App"> <div className="AppContainer"> <div className="PageTitle">Weather App</div> <LocationSearch showDropdown={showDropdown} searchResults={searchResults} onClickHandler={onClickHandler} onChangeHandler={onChangeHandler} /> </div> <div className="Footer"> Built with <a href="https://www.metaweather.com/">MetaWeather</a> </div> </div> ); } export default App;

Now try searching! You should see a dropdown populate below. You can click it too but nothing will happen other than the dropdown disappearing, because you’ve selected a location but we are not doing anything with it just yet!

We are going to take the selected location and display it in a nice little card.

In WeatherCard.js and WeatherCard.css paste the following

WeatherCard.js

import "./WeatherCard.css"; const WeatherCard = (props) => { const c2f = (c) => c * (9 / 5) + 32; const locationWeather = props.locationWeather; return ( <div className="WeatherCardContainer"> <div className="WeatherInfo"> <div className="Title">{locationWeather.title}</div> <div className="Temperature"> {c2f(locationWeather.the_temp).toFixed(1)}°F </div> <div className="Description">{locationWeather.weather_state_name}</div> </div> <div className="WeatherIcon"> <img src={`https://www.metaweather.com/static/img/weather/png/64/${locationWeather.weather_state_abbr}.png`} alt="weather" ></img> </div> </div> ); }; export default WeatherCard;

WeatherCard.css

.WeatherCardContainer{ display: flex; width:100%; flex-direction: row; justify-content: space-evenly; border-radius: 10px; padding: 10px 0; border: 1px solid black; margin-top:10px; }

Then modify your App.css to import the WeatherCard and display it in the app like this:

import "./App.css"; import { useState } from "react"; import WeatherCard from "./components/WeatherCard/WeatherCard"; import LocationSearch from "./components/LocationSearch/LocationSearch"; function App() { const [searchResults, setSearchResults] = useState([]); const [showDropdown, setShowDropdown] = useState(false); const [locationWeather, setLocationWeather] = useState(null);

const onChangeHandler = (evt) => { let locationSearchValue = evt.target.value; if (locationSearchValue === "") { setShowDropdown(false); setSearchResults([]); return; } let locationSearchQuery = `https://www.metaweather.com/api/location/search/?query=${locationSearchValue}`; fetch(locationSearchQuery) .then((res) => res.json()) .then((result) => { if (result.length > 0) { setShowDropdown(true); setSearchResults(result); } }); }; const onClickHandler = (id) => { let locationWeatherQuery = `https://www.metaweather.com/api/location/${id}/`; fetch(locationWeatherQuery) .then((res) => res.json()) .then((result) => { if (result.consolidated_weather.length > 0) { setLocationWeather({ ...result.consolidated_weather[0], title: result.title, }); } }); setShowDropdown(false); }; return ( <div className="App"> <div className="AppContainer"> <div className="PageTitle">Weather App</div> <LocationSearch showDropdown={showDropdown} searchResults={searchResults} onClickHandler={onClickHandler} onChangeHandler={onChangeHandler} /> {locationWeather && <WeatherCard locationWeather={locationWeather} />} </div> <div className="Footer"> Built with <a href="https://www.metaweather.com/">MetaWeather</a> </div> </div> ); } export default App;

Now try searching a location and clicking on it. You will see a weather card pop up with that locations weather!

Great! Now the application code is done. So how do we deploy it?

Deploying our app…

You will first need an AWS Free Tier account, it is usually free for a year before costs can start incurring. Always watch your resource usage and use proper permissions for users! Also you need to upload your code in a repository. I’ve uploaded mine to GitHub, but there are other options as well.

In your AWS console you want to search for AWS Amplify, once you are there click on Get Started

A web app is ok for now, so click on that.

You want to next pick the option for your repository where you’ve hosted your code.

Pick your repository branch

Confirm your build and test settings.

Then hit save and deploy!

Your app will then be created.

You can then hit the front-end environments tab to see your application’s status.

Our app has been deployed!

That’s all there is to it! We will explore the back-end options in the future. I’ve linked my GitHub repo below if you would like to see the code in full.

https://github.com/khansoul/weatherapp