CSE 154

Section 9: AJAX with Fetch

Section Agenda

QuickCheck

Review promises: Handling uncertainty

Review AJAX: Why is it useful? How do we use it?

Practice AJAX with text response

Promises

Promise States

Promises: Basic Review

let p = new Promise(executorFn)

Promises take a callback which knows how to resolve and reject the promise.

  • function executorFn(resolve, reject) { /* ... */ }

Within the executor, call the passed resolve and reject callbacks to change the state of the promise.

setTimeout(function() {
  if(Math.random() < 0.01) {
    resolve("You got lucky, this time...");
  } else {
    reject("There was a problem with the request. Oops!");
  }
}), 1000);

Promises: Then and Catch

We often use promises with asynchronous processes (like timeouts) in order to handle success and failure only once the process is done pending. We can trigger a callback upon success with .then and upon failure with .catch.

let p = new Promise(makeRequest)
  .then(processData)
  .then(processMoreData)
  .catch(handleError);

The callbacks will recieve the return value of the previous callback in the chain, or the argument to resolve()/reject().

In this course, we will not really make new Promises, however, AJAX fetch requests return Promises that we need to respond to with then and catch.

Promise Exercise: Mimikyu's Secret

This website can be logged into with with Username: Mimikyu and Password: BeMyFriend. HOWEVER! This stuff is top secret, so if you cannot enter the correct credentials within 10 seconds, you are not allowed in.

Promises handle uncertainty with asynchronous functions, such as timers and user-triggered events. Using this mostly complete starter code, make it so that Upon hitting "submit":

  • If the credentials are correct and under 10 seconds have passed, call revealSecret.
  • If more than 10 seconds have passed, call keepOut
  • If the credentials are wrong, call keepOut

Handle this behavior using promises. HINT: You may want a variable that keeps track of whether 10 seconds has passed, which you can refer to when the submit button is clicked.

AJAX

Why is it useful?

  • The web is full of data - often, websites "ask" for data from servers which hold different types of data (txt, json, images, databases, etc.)
  • What we know about JS so far does not give us any way to process data outside of our JS program. That's where AJAX comes in!

How do we use it?

  • fetch! (a built-in JavaScript function)
  • A touch of Promises to elegantly control success (200) vs. error (non-200) responses from a server

AJAX fetch template

When we make a call to fetch data (whether it's HTML, txt, JSON, etc) we use a function in JavaScript called fetch, which takes a URL path to fetch data from.

Here's the general template you will use for most AJAX code:


const URL_BASE = "";

// Step 1. Write a function to "fetch" data from a URL
function callAjax() {
  let url = URL_BASE + "?query0=value0"; // some requests require parameters
  fetch(url)
    .then(checkStatus)
    //.then(resp => resp.text()) // include if your data comes in text
    //.then(resp => resp.json()) // include if your data comes in JSON
    .then(processData)
    .catch(console.log);
}

// Step 2: Implement a function to process the respsonse data. You may want to break this apart
// into multiple functions.
function processData(responseData) {
  // Do something with your responseData! (build DOM, display messages, etc.)
}

// Step 3. Include the checkStatus function
function checkStatus(response) {
  if (!response.ok) { // response.status >= 200 && response.status < 300
     throw Error("Error in request: " + response.statusText);
  }
  return response;
}

JS

Mechanics

We initiate a fetch of a URL

  • A fetch call returns a Promise object
  • The .then method on a Promise object returns a Promise object
    • Our first .then(checkStatus) checks the status of the response to makes sure the server responded with an OK. The result of that first .then is another Promise object with the response as the value of the Promise.
    • We .then(resp => resp.json()) which also returns a Promise object with a JSON object as the value
    • We .then(processData) which will do something with the response from the server.
    • If at any time there is an error, the execution falls down to the .catch method on the Promise chain

Chaining of Promises gives us a nice data flow, like down a pipe!

The Promise Pipeline

Visual description of the fetch pipeline

Exercise 1: Number Trivia! (a public API example)

Numbers API screenshot

This is a short exercise, but shows how to use one of thousands of API's available publically on the web. Some are more complicated than others (this is a great example of the importance of clear documentation!) and some require tokens or keys (which is good for security reasons, but takes an extra step).

The Numbers API is one of the simplest APIs available to get started with fetching data from the web without needing a token.

Numbers API Details

Service URL: http://numbersapi.com/

Query Parameters (Required): number

Note: this API doesn't have the "query=value" format we saw in the other two web services - some APIs have a bit of a different format which you can find in the documentation.

Details: Replace number with any integer number (e.g. 154), or random to get trivia about a number. Response is returned as a single plain text string.

Example Requests

Using the Numbers API: A Simple Example

example output of number-trivia
            exercise

Given this starter numbers.html, write a JavaScript program numbers.js to take an integer value from a number text box and fetch a trivia fact about that number when the "Fetch Number Fact!" button is clicked, displaying the result text in the #output paragraph.

If the button is clicked but the text input is empty, or the "Fetch Random Number Fact!" button is clicked, a random number trivia fact should be fetched and displayed.

Exercise 1: Solution

Solution (JavaScript)

Exercise 2: Ajax Pets

Given this ajaxpets-starter.zip (HTML, CSS, and JS template), create an AJAX-powered gallery of pet images that allows you to switch between kitty and puppy images without reloading the page. You can view the finished product here.

super special ajax pets pet

Exercise 2: Ajax Pets API URL

Service URL: https://courses.cs.washington.edu/courses/cse154/webservices/pets/ajaxpets.php

Query Parameters (required):
?animal=value

Details: animal is the name of the query parameter you need to assign a value to. This API recognizes either a value of puppy or kitty.

Example Request (with puppy as the value):
https://courses.cs.washington.edu/courses/cse154/webservices/pets/ajaxpets.php?animal=puppy

Exercise 2: Ajax Pets API Response Format

Response Format: Plain Text


"https://path/to/pet/img0.jpg"
"https://path/to/pet/img1.jpg"
"https://path/to/pet/img2.jpg"
"https://path/to/pet/img3.jpg"
...
            

Template Plain Text Response

Exercise 1: Ajax Pets Implementation

The provided starter code includes a module-pattern template we've been using to get you started, named ajaxpets.js. You will need to implement the JavaScript to incorporate AJAX and make a request with the Ajax Pets API URL with the parameter animal of value kitty or puppy, depending on which radio button is selected.

When a request returns a response successfully with the plain text response of image paths, write JS to add img tags as children to the #pictures div for each image path returned on a new line.

Exercise 2: Solution

Solution (JavaScript)