The NASA API has an endpoint that allows us to retrieve Landsat 8 image for a specific date (date=2017-04-16) and location (lon=-122.3060, lat=47.6533) and link).
let data = {
"cloud_score": 0.3674638267064959,
"date": "2017-04-16T19:01:16",
"id": "LC8_L1T_TOA/LC80470272017106LGN00",
"resource": {
"dataset": "LC8_L1T_TOA",
"planet": "earth"
},
"service_version": "v1",
"url": "https://earthengine.googleapis.com/api/thumb?thumbid=a6793b04bb763f27283bd16f69f53ae6&token=d101cee0116e6f14891f3dbab8315dd0"
}
JSON
Link to resulting image. Where do you think this is?
let date = data.date; // date === "2017-04-16T19:01:16"
let cloud_score = data.cloud_score; // cloud_score === 0.3674638267064959
let planet = data.resource.planet; // planet === "earth"
let version = data.service_version; // version = "v1"
JS
Notes:
More on APIs
Testing with (hard coded) JSON
Intro to AJAX, fetch and promises
All of the class' teams group names (with student names) were typed into a .json
file which we will use in an example shortly.
The structure of the file is:
{
"teams": [
{
"name": "Catz",
"students": ["Jack", "Spot", "Whitney", "Charlie"]
},
{
"name": "Dawgs",
"students": ["Mowgli", "Ruby", "Moss"]
}
]
}
JSON
What could would you write to tell how many students groups there are and how many students are actually in a group?
let data = {
"teams": [
{
"name": "Catz",
"students": ["Jack", "Spot", "Whitney", "Charlie"]
},
...
}
let numTeams = data.teams.length; // numTeams === 44
let count = 0;
for (let i = 0; i < data.teams.length; i++) {
count += data.teams[i].students.length;
}
JSON
How many people do you think actually signed up for a group? 113
P.S. Handy JSON Formatter Chrome extension for viewing JSON
The Randomizer (now) uses the Randomizer API to get all of the team names and members.
The Randomizer Documentation can shed some light on how to get the data we need from this API
But how do we get that information into our web page????
(Click on the image and view page source on that page to see the example of the code...)
Get the data from the server, add it to our .js file (loadTeamsTest), and then test our site with this "hard coded" text. We can ensure we are creating/removing our DOM elements correctly this way!
function loadTeamsTest() {
data = {
"teams": [
{
"name": "Catz",
"students": ["Jack", "Spot", "Whitney", "Charlie"]
},
{
"name": "Dawgs",
"students": ["Mowgli", "Ruby", "Moss"]
}
]
};
id("randomize").disabled = false;
}
JS
But what if the data changes frequently (i.e. we get Groupizer to work)?
A way to use Javascript to pull in more content from the server without navigating the page to a new url.
We are showing you this for context only, DO NOT USE the "XML over HTTP" method of AJAX calls in this class. Read todays reading for why not.
let xhr = new XMLHttpRequest();
xhr.open(method, url, [async/sync]);
xhr.onload = function() { /* handle success */ };
xhr.onerror = function() { /* handle failure */ };
xhr.send();
JS (template)
let xhr = new XMLHttpRequest();
xhr.open("GET", "data.txt");
xhr.onload = function() { alert(this.responseText); };
xhr.onerror = function() { alert("ERROR!"); };
xhr.send();
JS (example)
The XMLHttpRequest
object can be used synchronously or asynchronously.
So this functionality could be called S/AJAX or A/SJAX. But AJAX has a nice ring to it.
It's better to use async so that the page doesn't block waiting for the page to come back.
We will not use AJAX synchronously in this class.
the XMLHttpRequest
object can be used to fetch anything that you
can fetch with your browser.
This includes XML (like in the name), but also JSON, HTML, plain text, media files.
So it could be called AJAJ or AJAH or AJAT. But AJAX has a nice ring to it.
The Fetch API was created in 2014 and incorporated into the window
DOM object.
We will be using AJAX with Fetch in this class.
(function() {
...
function doWebRequest() {
let url = ..... // put url string here
fetch(url);
// Note: there needs to be more here
// process data and catch errors
}
})();
JS (template)
You can use the absolute path to a file (a full URL) as the parameter to
fetch
const URL = "https://courses.cs.washington.edu/courses/cse154/19sp/tools/randomizer/randomizer.php";
...
function loadTeams() {
fetch(url + "?mode=text");
...
}
JS (example)
You can also use a relative path name to fetch
from a file that is
retreived from the same directory on the server as the .js
file.
const URL = "randomizer.php";
...
function loadTeams() {
fetch(url + "?mode=text");
...
}
JS (example)
Now that we've done a fetch
, we need to do something with the data that
comes back from the server.
But we don't know how long that will take or if it even will come back correctly!
The fetch
call returns a Promise
object which will help
us with this uncertainty.
Promises have three states:
Example: “I promise to post HW 3”
Pending: Not yet posted
Fulfilled: HW 3 posted
Rejected: Wrong homework posted, or not posted in time
Promise
sPromises have three states:
...
let promise = new Promise(action);
...
function action(resolve, reject) {
// do pending uncertain action
// (like make an AJAX call)
if (success) {
resolve(); // Fulfilled
} else {
reject(); // Rejected
}
}
JS (template)
Promise
is returned from a fetch
call
We will be using promises when we fetch
information from a
server, which is an uncertain task
We give you "boilerplate" starting code because you will use this frequently
fetch
Code Skeleton (text response)
const BASE_URL = /* put base url string here */;
...
function callAjax() {
let url = BASE_URL /* + any query parameters */;
fetch(url)
.then(checkStatus)
.then(function(responseText) {
//success: do something with the responseText
})
.catch(function(error) {
//error: do something with error
});
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response.text();
} else {
return Promise.reject(new Error(response.status + ": " + response.statusText));
}
}
JS (template)
Found from ajax-template-documented.js
fetch
Code Skeleton (text)
const BASE_URL = /* put base url string here */;
...
function callAjax() {
let url = BASE_URL /* + any query parameters */;
fetch(url)
.then(checkStatus)
.then(handeResponse)
.catch(handleErrror);
}
function handleResponse(responseText) {
//success: do something with the responseText
}
function handleError(error) {
//error: do something with error
}
function checkStatus(response) { // boiler plate code given out
...
}
JS (template)
fetch
Code Skeleton (with JSON)
What if the resulting text comes back as JSON format?
const BASE_URL = /* put base url string here */;
...
function callAjax() {
let url = BASE_URL /* + any query parameters */;
fetch(url)
.then(checkStatus)
.then(JSON.parse) // parse the response string into a JSON object
.then(handeResponse)
.catch(handleErrror);
}
function handleResponse(responseJSON) {
// now handle this response as a JSON object.
}
function handleError(error) {
// error handling doesn't change
}
JS (template)
We initiate a fetch
of a URL
fetch
call returns a Promise
object.then
method on a Promise
object returns a Promise
object.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 (text, JSON, ...) as the value of the Promise.
.then(JSON.parse)
which also returns
a Promise
object with a JSON object as the value
.then(handleResponse)
which will do something with the response
from the server.
.catch
method on the Promise
chain
Chaining of Promises gives us a nice data flow, like down a pipe!
They help deal with code that has an uncertain outcome
They separate the completion of the fetch request from the page logic
function loadTeamsTxt() {
const url = URL + "?mode=text";
fetch(url)
.then(checkStatus)
.then(handleLoadTeams)
.catch(console.log);
}
function loadTeamsJSON() {
const url = URL + "?mode=json";
fetch(url)
.then(checkStatus)
.then(JSON.parse)
.then(handleLoadTeams)
.catch(console.log);
}
JS
The help deal with uncertainty in your code. You never know exactly what will happen when you make an AJAX call, so wrapping the call in a Promise is a nice way to deal with the uncertainty.
The paradigm is nice because you write the anonymous function that defines the promise, so you are the one who writes the code that determines whether the promise was 'fulfilled' or 'rejected'.
You also define what happens after the Promise fulfills with the
then
function, and what happens when it rejects in the
catch
function.