Marcy Lab School Docs
  • Welcome
  • Student Guidelines & Policies
    • Student Handbook
    • AI Policy
    • Academic Calendar
  • Environment Setup
    • Local Environment Setup - Mac
    • Local Environment Setup - Windows
    • GitHub Setup
    • Postgres Setup
  • How-Tos
    • How To Code at Marcy: Code Style Guide
    • How to Do Short Response and Coding Assignments
    • How to Debug
    • How to PEDAC
    • How to Create A GitHub Organization and Scrumboard
    • How to Create Projects with Vite
    • How to Deploy on GitHub Pages
    • How to Deploy on Render
    • How to Test your API with Postman
  • Mod 0 - Command Line Interfaces, Git, and GitHub
    • Overview
    • 1. Command Line Interfaces
    • 2. Git & GitHub
    • 3. Git Pulling & Merging
    • 4. Git Branching & PRs
  • Mod 1 - JavaScript Fundamentals
    • Overview
    • 1. Intro to Programming
    • 2. Errors
    • 3. Node & Node Modules
    • 4. Variables, Functions & String Methods
    • 5. Control Flow, typeof, and Math
    • 6. Loops
    • 7. Arrays
    • 8. Objects
    • 9. Higher Order Functions: Callbacks
    • 10. Higher Order Functions: Array Methods
    • 11. Regex
  • Mod 2 - HTML, CSS & the DOM
    • Overview
    • 1. HTML
    • 2. CSS
    • 3. Accessibility (a11y)
    • 4. The Document Object Model (DOM) API
    • 5. Events
    • 6. Forms
    • 7. The Box Model and Positioning
    • 8. Flexbox
    • 9. Grid & Media Queries
    • 10. ESModules
    • 11. Vite
    • 12. LocalStorage
  • Mod 3 - Async & APIs
    • Overview
    • 1. Promises
    • 2. Fetch
    • 3. Building a Fetching App
    • 4. Async & Await
    • 5. A Generic Fetch Handler
  • Mod 4 - Project Week!
    • Important How Tos and Guides
      • How to Create a GitHub Organization and Scrum Board
      • How To Start a Project with Vite
      • How To Deploy a Project with GitHub Pages
    • Project Week Overview
    • Agile Methodologies
    • Deliverables & Milestones
    • Technical Requirements Checklist
    • Free API List
    • Collaborative GitHub
  • Mod 5 - Object-Oriented Programming
    • Overview
    • 1. Intro to OOP, Encapsulation, Factory Functions, and Closure
    • 2. Classes
    • 3. Private & Static
    • 4. UML Diagrams & Has Many/Belongs To Relationships
    • 5. Challenge: Implementing Has Many/Belongs To
    • 6. Inheritance
    • 7. Polymorphism
    • 8. Review and Practice
    • MDN: Object Prototypes
  • Mod 6 - Data Structures & Algorithms
    • Overview
    • Important How Tos and Guides
      • How to Debug
      • How to PEDAC
    • 1. Nodes & Linked Lists
    • 2. Singly & Doubly Linked Lists
    • 3. Stacks & Queues
    • 4. Recursion
    • 5. Trees
  • Mod 7 - React
    • Overview
    • Important How Tos and Guides
      • How to Create Projects with Vite
      • How to Deploy on GitHub Pages
    • 1. Intro to React
    • 2. Events, State, and Forms
    • 3. Fetching with useEffect
    • 4. React Router
    • 5. Building a Flashcards App
    • 6. React Context
    • 7. Global Context Pattern
  • Mod 8 - Backend
    • Overview
    • Important How Tos and Guides
      • How to Deploy on Render
      • How to Test your API with Postman
      • Postgres Setup
    • 1. Intro to Express
    • 2. Building a Static Web Server with Middleware
    • 3. Securing API Keys and Environment Variables
    • 4. RESTful CRUD API
    • 5. Model-View-Controller Architecture
    • 6. SQL and Databases
    • 7. JOIN (Association) SQL Queries
    • 8. Knex
    • 9. Your First Fullstack App!
    • 10. Migrations & Seeds
    • 11. Schema Design & Normalization
    • 12. Hashing Passwords with Bcrypt
    • 13. React Express Auth Template Overview
  • Mod 9 - Civic Tech Hackathon
    • Overview
    • Rubric
  • Mod 10 - Capstone
    • Overview
Powered by GitBook
On this page
  • Video
  • Setup
  • Plan
  • HTML
  • JavaScript Separation of Concerns
  • Fetching
  • Putting it Together
  • Rendering
  • Adding Form Handling
  1. Mod 3 - Async & APIs

3. Building a Fetching App

Previous2. FetchNext4. Async & Await

Last updated 5 months ago

Video

Watch the full build tutorial here!

Setup

Create a new repository and clone it down. CD and then:

`npm create vite`
# name: app
# Framework: Vanilla
# Variant: JavaScript

cd into app and npm i

Remove the starter code.

Plan

Before you build anything, draw a wireframe:

Then plan out the logic:

  • When the page loads:

    • fetch pikachu (make sure to catch any errors)

    • render pikachu data to the screen

    • add an event listener for the form

  • When the form is submitted:

    • grab data from the form

    • use that data to fetch a new pokemon (make sure to catch any errors)

    • render that pokemon to the screen

HTML

First, we'll create the structure. We want:

  1. An h1 heading with some title

  2. A form to search for a pokemon. It should have:

    1. An h2 heading with a form title

    2. A label and input:text combo for the pokemon name.

    3. A button to submit the form

  3. A section to display pokemon information. It will have two sections and we'll make it display: flex to put them side by side:

    1. A div to display the pokemon picture and name

    2. A div with a ul to display the pokemon stats

Here's the HTML we came up with, added to the div#app container:

<div id="app">
  <h1>Pokedex</h1>
  <form id="pokemon-form">
    <h2>Search for a Pokemon</h2>
    <label for="pokemon-name">Name</label>
    <input type="text" id="pokemon-name" name="pokemonName">
    <button>Search</button>
  </form>
  <section id="pokemon-info-container">
    <div id="pokemon-picture">
      <img src="" alt="">
      <p id="pokemon-picture-name">Pokemon loading...</p>
    </div>
    <div id="pokemon-stats">
      <h2>Pokemon Stats</h2>
      <ul id="pokemon-stats-list">
        <!-- dynamically added list items go here -->
      </ul>
    </div>
  </section>
</div>

JavaScript Separation of Concerns

Rather than writing all of your code in one place, separate your code into three files:

  • src/fetching-helpers.js - exports functions related to fetching data from specific Web APIs

  • src/dom-helpers.js - exports functions related to dom manipulation

  • src/main.js - pulls together functions from helper files and invokes them. Defines event handlers if needed.

After creating these files, we can put the outline of some functions inside:

// fetching-helpers.js
export const fetchPokemon = (pokemonName) => {
  console.log("fetching pokemon: " + pokemonName);
}

// dom-helpers.js
export const showPokemon = (pokemonData) => {
  console.log("rendering pokemon: " + pokemonData)
}

// main.js
import { fetchPokemon } from ./fetching-helpers.js
import { showPokemon } from ./dom-helpers.js

const main = () => {
  fetchPokemon("pikachu");
};

main();

Start with fetching data from the API since that the data we get back will tell us what information we can render. We'll use pikachu as the test input for now.

Fetching

In fetching-helpers.js, we can create a fetchPokemon function that takes in a pokemonName and searches the PokeAPI for that pokemon:

export const fetchPokemon = (pokemonName) => {
  console.log('fetching pokemon ' + pokemonName)

  // 2. Define promise handlers with .then and .catch
  return fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonName}`)
    .then((response) => {
      // 3. Check that the response is ok. If it isn't throw a useful error.
      if (!response.ok) {
        throw Error(`Fetch failed. ${response.status} ${response.statusText}`)
      }

      // 4. Start reading the response body's ReadableStream and return the promise
      return response.json();
    })
    .then((pokemonData) => {
      console.log(pokemonData);
      return pokemonData;
    })
    .catch((err) => {
      // 6. Handle Errors
      console.error(err);
    })
};

This file only cares about fetching the pokemonData from the response body's ReadableStream. Once we get that data, this function has done its job. It will return pokemonData wrapped in a Promise.

Putting it Together

Remember how we set up showPokemon in dom-helpers.js?

// dom-helpers.js
export const showPokemon = (pokemonData) => {
  console.log("rendering pokemon: " + pokemonData)
}

Because of this forward thinking, in main.js, we can already link up fetchPokemon with showPokemon by invoking showPokemon when the promise returned by fetchPokemon resolves.

// main.js
import { fetchPokemon } from ./fetching-helpers.js
import { showPokemon } from ./dom-helpers.js

const main = () => {
  fetchPokemon("pikachu")
    .then((pokemonData) => {
      showPokemon(pokemonData)
    });
  
  /* or in one line if you want to be fancy:

  fetchPokemon("pikachu").then(showPokemon);

  */
};

main();

The pokemonData that the fetchPokemon promise resolves to will be passed to and printed out by showPokemon.

Rendering

In dom-helpers.js, the final step is rendering the pokemon! This requires us to look at the API more closely to see the structure of the data we're dealing with.

Printing out the pokemonData is a helpful way to see the data structure first. We can see that we care about the following data:

  • pokemonData.sprites — an object of pokemon images

  • pokemonData.name — the name of the pokemon

export const showPokemon = (pokemonData) => {
  console.log("rendering pokemon: " + pokemonData)
  
  const img = document.querySelector('#pokemon-picture>img')
  const nameP = document.querySelector('#pokemon-picture-name');

  img.src = pokemonData.sprites.front_default;
  nameP.textContent = pokemonData.name
}

Adding Form Handling

Because of the beautiful separation of concerns, adding in form functionality is easy. We just grab the pokemonName data from the form, pass it to fetchPokemon, and showPokemon when the promise resolves!

const handleSubmit = (e) => {
  e.preventDefault();
  const form = e.target;
  const pokemonName = form.pokemonName.value;

  fetchPokemon(pokemonName).then(showPokemon);
  
  form.reset();
}

const main = () => {
  fetchPokemon('pikachu').then(showPokemon);

  document
    .querySelector('form')
    .addEventListener('submit', handleSubmit)
}

main();