HTTP Requests

Creating calls to various APIs using 4 techniques

Summary:

  1. JavaScript is the language of the web because of its asynchronous capabilities. AJAX, which stands for Asynchronous JavaScript and XML, is a set of tools that are used together to take advantage of JavaScript’s asynchronous capabilities.

  2. There are many HTTP request methods, two of which are GET and POST.

  3. GET requests only request information from other sources.

  4. POST methods can introduce new information to other sources in addition to requesting it.

  5. GET requests can be written using an XMLHttpRequest object and vanilla JavaScript.

  6. POST requests can also be written using an XMLHttpRequest object and vanilla JavaScript.

  7. Writing GET and POST requests with XHR objects and vanilla JavaScript requires constructing the XHR object using new, setting the responseType, creating a function that will handle the response object, and opening and sending the request.

  8. To add a query string to a URL endpoint you can use ? and include a parameter.

  9. To provide additional parameters, use & and then include a key-value pair, joined by =.

  10. Determining how to correctly write the requests and how to properly implement them requires carefully reading the documentation of the API with which you’re working.

Four HTTP Requests

The four most commonly used types of HTTP requests are GET, POST, PUT, and DELETE.

  • GET : retrieving info from a website

  • POST : posting info to the source

Perform GET and POST requests using JavaScript's XHR object :

  1. Datamuse API for GET requests

  2. Rebrandly URL shortener API for POST requests

GET Requests : Asynchronous JavaScript & XML (AJAX)

  • enables requests to be made after initial page load

  • How to create an XHR GET request:

# XHR GET Requests

This section we create the boiler plate code for an AJAX GET request using an XMLHttpRequest Object:

const xhr = new XMLHttpRequest();
const url = "https://api-to-call.com/endpoint";
xhr.responseType = 'json'; //format the response in Javascript Object Notation
xhr.onreadystatechange = () => {
  if (xhr.readyState === XMLHttpRequest.DONE) {    //check if request is finished
    return xhr.response;  // This response will contain the data that we’re
    // getting back from the request.       
  }
}

xhr.open('GET', url); //.open() creates new request, pass in type and request url
xhr.send()

# Using AJAX GET request to Datamuse API to search for words that rhyme

// Information to reach API
const url = "https://api.datamuse.com/words?"; //direct requests here
const queryParams = 'rel_rhy='; // start of query string to find words that rhyme

// Selecting page elements
const inputField = document.querySelector('#input');
const submit = document.querySelector('#submit');
const responseField = document.querySelector('#responseField');

// AJAX function
const getSuggestions = () => {
  const wordQuery = inputField.value;
  const endpoint = `${url}${queryParams}${wordQuery}`;
  const xhr = new XMLHttpRequest();
  xhr.responseType = 'json';
  xhr.onreadystatechange = () =>{
      if(xhr.readyState === XMLHttpRequest.DONE) {
        renderResponse(xhr.response);   //use renderRawResponse() to see raw data --> need another helper file for this script 
      }
  }
  xhr.open('GET', endpoint); //endpoint is destination
  xhr.send(); //send request to server
}

// Clear previous results and display results to webpage
const displaySuggestions = (event) => {
  event.preventDefault();
  while(responseField.firstChild){
    responseField.removeChild(responseField.firstChild);
  };
  getSuggestions();
}

submit.addEventListener('click', displaySuggestions);

In this exercise, we will create a request to set a topic and find adjectives that describe the input word using query strings.

A query string contains additional information to be sent with a request. The Datamuse API allows us to retrieve more specific data with query strings attached to the request URL.

A query string is separated from the URL using a ? character. After ?, you can then create a parameter which is a key value pair joined by a =. Examine the example below:

'https://api.datamuse.com/words?key=value'

If you want to add an additional parameter you will have to use the & character to separate your parameters. Like so:

'https://api.datamuse.com/words?key=value&anotherKey=anotherValue'

XHR POST Requests

The major difference between a GET request and POST request is that a POST request requires additional information to be sent through the request. This additional information is sent in the body of the post request.

# Standard Boiler plate code for POST Requests

const xhr = new XMLHttpRequest();
const url = "https://api-to-call.com/endpoint";
const data = JSON.stringify({id: '200'});
// this converts a value to a JSON string, enabling us to send data to server
xhr.responseType = 'json';
// the below contain handler for when xhr state changes
xhr.onreadystatechange = () => {
  if (xhr.readyState === XMLHttpRequest.DONE) {
    return xhr.response;
  }
}

xhr.open('POST', url);
xhr.send(data); // this the only diff between GET and POST
//POST will send data in

# Using Rebrandly API to shorten long URLs

// Information to reach API
const apiKey = '49dbc48d3d2548d29a5c6bae1bc7deb9'; //rebrandly api key
const url = 'https://api.rebrandly.com/v1/links';

// Some page elements
const inputField = document.querySelector('#input');
const shortenButton = document.querySelector('#shorten');
const responseField = document.querySelector('#responseField');

// AJAX functions
const shortenUrl = () => {
  const urlToShorten = inputField.value;
  const data = JSON.stringify({destination: urlToShorten});
  const xhr = new XMLHttpRequest();
  xhr.responseType = 'json';
  xhr.onreadystatechange = () => {
    if (xhr.readyState === XMLHttpRequest.DONE) {
      renderResponse(xhr.response);
    }
  }
  xhr.open('POST', url);
  xhr.setRequestHeader('Content-type', 'application/json');
xhr.setRequestHeader('apikey', apiKey);
  xhr.send(data);

}
// Clear page and call AJAX functions
const displayShortUrl = (event) => {
  event.preventDefault();
  while(responseField.firstChild){
    responseField.removeChild(responseField.firstChild);
  }
  shortenUrl();
}

shortenButton.addEventListener('click', displayShortUrl);
// Input : https://medium.com/@codecademy/breaking-the-coding-language-barrier-bf24652c3c60
//Output : Your shortened url is: rebrand.ly/oa3uv8w

Combining Promises to AJAX

This section we learn to use fetch(), which uses promises to handle requests. Then, we will simplify requests using async and await.

We’ll use the Datamuse API for GET requests and Rebrandly URL Shortener API for POST requests.

# fetch() to GET request

Sample:

  • Inside of the response callback function, check the ok property of response inside of a conditional statement. In the code block of the conditional statement, return response.json().

  • The reason we’re testing the ok property of the response object is that it will be a Boolean value. If there were no errors response.ok will be true and then your code will return response.json().

  • Add a second argument to .then(), it will be an arrow function that will handle our failures. Separate the first callback function from the second with a comma. The second callback function takes a single parameter, networkError.

    In the code block of the second callback function, log networkError.message to the console.

    If we could not reach the endpoint at all, e.g., the server is down, then we would get this networkError.

  • Chain another .then() method to the end of the first .then() method.

    Pass the new .then() method a callback function that takes jsonResponse as its parameter and return jsonResponse.

    The second .then()‘s success callback won’t run until the previous .then() method has finished running. It will also not run if there was an error was thrown previously.

// BOILER PLATE CODE FOR GET using fetch() and .then()
fetch('https://api-to-call.com/endpoint').then(response => {
  if (response.ok) {
    return response.json();
  }
  throw new Error('Request failed!');
}, networkError => {
  console.log(networkError.message);
}).then(jsonResponse => {
  return jsonResponse;
});

The fetch() function:

  • Creates a request object that contains relevant information that an API needs.

  • Sends that request object to the API endpoint provided.

  • Returns a promise that ultimately resolves to a response object, which contains the status of the promise with information the API sent back.

Extension of the datamuse API project:

// Information to reach API
const url = 'https://api.datamuse.com/words';
const queryParams = '?sl=';

// Selects page elements
const inputField = document.querySelector('#input');
const submit = document.querySelector('#submit');
const responseField = document.querySelector('#responseField');

// AJAX function
const getSuggestions = () => {
  const wordQuery = inputField.value;
  const endpoint = `${url}${queryParams}${wordQuery}`;
  
  fetch(endpoint, {cache: 'no-cache'}).then(response => {
    if (response.ok) {
      return response.json();
    }
    throw new Error('Request failed!');
  }, networkError => {
    console.log(networkError.message)
  })
}

// Clears previous results and display results to webpage
const displaySuggestions = (event) => {
  event.preventDefault();
  while(responseField.firstChild){
    responseField.removeChild(responseField.firstChild);
  }
  getSuggestions();
};

submit.addEventListener('click', displaySuggestions);

# fetch() POST Requests

Notice that the initial call takes two arguments: an endpoint and an object that contains information needed for the POST request. The rest of the request is identical to the GET request.

fetch('https://api-to-call.com/endpoint', {
  method: 'POST',
  body: JSON.stringify({id: "200"})
}).then(response => {
  if(response.ok){
	  return response.json();  
  }
	throw new Error('Request failed!');
}, networkError => {
  console.log(networkError.message);
}).then(jsonResponse => {
  console.log(jsonResponse);
})

//using Rebrandly API key with the boiler plate code
// Information to reach API
const apiKey = '<Your API Key>';
const url = 'https://api.rebrandly.com/v1/links';

// Some page elements
const inputField = document.querySelector('#input');
const shortenButton = document.querySelector('#shorten');
const responseField = document.querySelector('#responseField');

// AJAX functions
const shortenUrl = () => {
  const urlToShorten = inputField.value;
  const data = JSON.stringify({destination: urlToShorten})
  
	fetch(url, {
    method: 'POST',
    headers: {
      'Content-type': 'application/json',
      'apikey': apiKey
    },
    body: data
  })
}

// Clear page and call AJAX functions
const displayShortUrl = (event) => {
  event.preventDefault();
  while(responseField.firstChild){
    responseField.removeChild(responseField.firstChild)
  }
  shortenUrl();
}

shortenButton.addEventListener('click', displayShortUrl);

Async GET Requests

we’re going to take what you’ve learned about chaining Promises and make it simpler using functionality introduced in ES8: async and await.

Review

  • Using an async function that will return a promise.

  • await can only be used in an async function. await allows a program to run while waiting for a promise to resolve.

  • In a try...catch statement, code in the try block will be run and in the event of an exception/error, the code in the catch statement will run.

//BOILERPLATE CODE for GET requests using ASYNC AWAIT
const getData = async () => {
  try {
    const response = await fetch('https://api-to-call.com/endpoint');
    if (response.ok) {
      const jsonResponse = await response.json();
      return jsonResponse;
    }
    throw new Error('Request failed!');
  } catch (error) {
    console.log(error);	
  }
}
  • Inside the catch code block, log error to the console.

Since this exercise is an example, we’re using console.log() to view the error. Generally, developers create a more sophisticated way of handling the error, like redirecting their users to another page, but logging is fine for us at the moment.

  • We’ll have to save the returned promise in a variable called response using the const keyword. response will save the response of endpoint once that information has been sent back.

  • Under response, create a conditional statement that checks if the ok property of the response object evaluates to a truthy value.

  • Inside the code block of the conditional statement, await the resolution of calling the .json() method on response.

    Save the returned object to a variable called jsonResponse using the keyword const.

    Since .json() is an asynchronous method we have to await until the promise status is resolved. Then we store the value to know what data the JSON holds.

// DATAMUSE API SAMPLE CODE
// Information to reach API
const url = 'https://api.datamuse.com/words?';
const queryParams = 'rel_jja=';

// Selecting page elements
const inputField = document.querySelector('#input');
const submit = document.querySelector('#submit');
const responseField = document.querySelector('#responseField');

// AJAX function
// Code goes here
const getSuggestions = async () => {
  const wordQuery = inputField.value;
  const endpoint = `${url}${queryParams}${wordQuery}`;
  try {
    const response = await fetch(endpoint, {cache: 'no-cache'});
    if(response.ok){
      const jsonResponse = await response.json();
      renderResponse(jsonResponse);
    }
  } catch (error) {
    console.log(error);
  }
}

// Clear previous results and display results to webpage
const displaySuggestions = (event) => {
  event.preventDefault();
  while(responseField.firstChild){
    responseField.removeChild(responseField.firstChild);
  }
  getSuggestions();
}

submit.addEventListener('click', displaySuggestions);

Async POST Requests

Review :

  1. GET and POST requests can be created a variety of ways.

  2. Use AJAX to asynchronously request data from APIs. fetch() and async/await are new functionalities developed in ES6 (promises) and ES8 respectively.

  3. Promises are a new type of JavaScript object that represent data that will eventually be returned from a request.

  4. fetch() is a web API that can be used to create requests. fetch() will return promises.

  5. We can chain .then() methods to handle promises returned by fetch().

  6. The .json() method converts a returned promise to a JSON object.

  7. async is a keyword that is used to create functions that will return promises.

  8. await is a keyword that is used to tell a program to continue moving through the message queue while a promise resolves.

  9. await can only be used within functions declared with async.

As with the other GET and POST requests that you’ve been making, an async POST request requires more information. Take a look at the diagram.

We still have the same structure of using try and catch as before. But, in the fetch() call, we now have to include an additional argument that contains more information like method and body.

Project using Foursquare & OpenWeather API

To be continued 1/12/2021

Last updated