# Fetch API
- Getting data from an API or from a database is a tree-stap action
- Calling the
fetch()
methode to starts a request
Thefetch()
methode returns a promise (see later in this course) - When the request completes, the promise resolves a response object
- This response returns a lot of information, but the actual data can be extracted in JSON format (with
response.json()
) or in raw text (withresponse.text()
)
- Calling the
- The response of the
fetch()
methode will pass through the chain (one or more) of.then()
handlers to process the data and a.catch()
handler to process the errors
fetch().then().then().then().catch();
IMPORTANT
- Every
.then()
handlers MUST returns something so it can be used as input data for the next.then()
handler - With the the
fetch()
methode, the first.then()
handlers always must returnsresponse.json()
(if the response is in JSON format) orresponse.text()
(if the response is just raw text)
fetch()
can handle all the different HTTP verb methodes (opens new window) you can expect from a CRUD (Create, Read, Update and Delete)
verb (methode) | action | description |
---|---|---|
GET | read | get date from an API, database, ... |
POST | create | post date to an API, add data to a database, ... |
PATCH/PUT | update | update a record in the database, ... |
DELETE | delete | delete a record from the database, ... |
- The
fetch(url, options)
methode accept two parameters:url
: the URL to fetch fromoptions
: some optional parameters
- A full description of all options can be found here (opens new window)
The ones you use the most are:
option | possible values |
---|---|
method | GET (default), POST , PUT , DELETE , ... |
headers | 'Content-Type': 'application/json' , ... |
body | JSON.stringify(data) , ...( data type must match Content-Type header) |
# Basic HTTP verbs
- To demonstrate a very basic example of the different verbs, we use the https://reqres.in/ (opens new window) API
- This is a fake API where the create, update and delete actions are not actually taking place, but the response 'fakes' this is really happens
# GET
- Use the
get
methode to retrieve data from an API or from a database - You don't have to explicitly set this methode, because this is the default methode when for
fetch()
- To retrieve information with
fetch()
, you only have to pass the URL as a parameter - Open es6/fetch/get.html and es6/fetch/get.js
- This example gets all the users on page 2 with this URL: https://reqres.in/api/users?page=2 (opens new window)
- We are only interested in the key
data
witch contains an array of six users
HTML
JavaScript
result
<div class="border-gray row" id="users"></div>
Copied!
1
# POST
- Use the
POST
methode to send new data to an API or insert something in a database - The data that will be sent to the API and the methode (
POST
) are past to theoptions
parameters of thefetch()
methode - Open es6/fetch/post.html and es6/fetch/post.js
HTML
JavaScript
result
<div class="border-gray row" id="user"></div>
Copied!
1
# PATCH/PUT
- Use the
PATCH
(orPUT
) methode to update data through an API or update something in a database - The data that will be sent to the API and the methode (
PATCH
) are past to theoptions
parameters of thefetch()
methode - Open es6/fetch/patch.html and es6/fetch/patch.js
HTML
JavaScript
result
<div class="border-gray row" id="user"></div>
Copied!
1
# DELETE
- Use the
DELETE
methode to delete data through an API or delete something from a database - The methode (
DELETE
) is past to theoptions
parameters of thefetch()
methode - Open es6/fetch/delete.html and es6/fetch/delete.js
HTML
JavaScript
result
<div class="border-gray row" id="user"></div>
Copied!
1
# Error handling
- The
fetch()
promise will reject (trow an error that will be handled bij thecatch()
) handler ONLY if:- a network error occurs
- a CORS (opens new window) header is sent by the server
- the base URL don't exists
- In every other situation e.g: faulty parameters on the URL, access not allowed, etc... the
fetch()
promise will resolve, and you have to deal with these kind of errors yourself - This can be easily done within the first
then()
handler, just before returningresponse.json()
- When we look at the response object (opens new window), there are tree properties we can use to test the status of the
response (look at the result tab on the
GET
and theDELETE
example)
property | description |
---|---|
status | status code (opens new window) e.g: 200 (ok), 404 (not found), 403 (forbidden), ... |
ok | true if status code is in the range of 2xx otherwise false |
statusText | which corresponds to the HTTP status code (but most of the time this string is empty) |
- Now you can trow an error if
response.ok
isfalse
, else sentresponse.json()
to the nextthen()
handler - Some possible scenarios to respond to an error:
scenario 1
scenario 2
- if
response.ok
isfalse
, trow a newError
object and let thecatch()
handler do the rest
fetch(url, options) .then((response) => { if (!response.ok) { throw Error(`Fetch error code ${response.status}`); } return response.json(); //we only get here if there is no error }) .then((res) => { // do something with the response }) .catch((error) => console.error(error));
Copied!
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- Open es6/fetch/error.html and es6/fetch/error.js
- This time we use jsonplaceholder (opens new window), another frequently uses fake API
- Open the console and look what's inside
response.ok
,response.code
and the error message
JavaScript
result 1
result 2
result 3
const url = 'https://jsonplaceholder.typicode.com/users/1'; // const url = 'https://jsonplaceholder.typicode.com/users/1111111'; // const url = 'https://nonexistingurl.com/users/1'; function getUser() { fetch(url) .then((response) => { console.log('response', response); if (!response.ok) { if (response.status === 404) throw Error('The requested user was not found'); throw Error('Something went wrong with your request'); } return response.json(); }) .then((user) => { console.log('User found', user); }) .catch((error) => { console.error(error); }); } getUser();
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Preloader
- Fetching data from an API sometimes takes a few seconds
- It's always a good idea to show your visitors some kind visual information that something is happening in the background
- This can be in the form af a preloader, a pinner or a simple text message
- Show the preloader just before fetching the data and hide the preloader when the data is rendered to the page or when an error occurred
function getUser() { fetch(url, options) .then((response) => { ... }) .then((res) => { // do something with the response preloader.style.display = 'none' }) .catch((error) => { console.error(error); preloader.style.display = 'none' }); } preloader.style.display = 'block'; getUser();
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# Examples
As we will not be using a backend of our own in this course, we will only discuss examples where we are retrieving data from external API's
# Fetch images
- Open /es6/fetch/images.html and /es6/fetch/images.js
- In this example we fetch all images from our own (fake) API:
https://my-json-server.typicode.com/pverhaert/itf-api/picsum (opens new window)
HTML
JavaScript
result
<div class="spinner tertiary"></div> <div class="row" id="imgContainer"></div>
Copied!
1
2
2
# Fetch movie info
- Open /es6/fetch/omdb.html and /es6/fetch/omdb.js
- Serialize form (opens new window)
- In this example we fetch movie information from the OMDb API (opens new window)
- The parameters we needed are:
apikey
: your API key (you must first generate a free apikey (opens new window))t
: the movie title to search fory
: year of releaseplot
: can befull
orshort
- The JSON we get from te server: https://www.omdbapi.com/?apikey=yourKey&t=Pulp+fiction&y=&plot=short (opens new window)
(ReplaceyourKey
in the query string with a real API key)
HTML
JavaScript
result
- line 2: replace the value for apikey with your API key
- As you can see in the form, the
name
attribute of the form elements matches exactly the keys for the query string we have to append to the fetch URL - This makes it super easy (only three lines of code) to serialize the form (opens new window) with JavaScript
The result of this serialization is a string like this:apikey=yourKey&t=Pulp+fiction&y=&plot=short
<form> <input type="hidden" name="apikey" value="yourKey" /> <div class="row responsive-label"> <div class="col-sm-12 col-md-2"><label for="title" class="doc">Title</label></div> <div class="col-sm-12 col-md"> <input type="text" placeholder="Title" id="title" name="t" value="Pulp fiction" required /> </div> </div> <div class="row responsive-label"> <div class="col-sm-12 col-md-2"><label for="year">Year</label></div> <div class="col-sm-12 col-md"> <input type="number" placeholder="Year" id="year" name="y" /> </div> </div> <div class="row responsive-label"> <div class="col-sm-12 col-md-2"><label for="plot">Plot</label></div> <div class="col-sm-12 col-md"> <select id="plot" name="plot"> <option value="short">short</option> <option value="full">full</option> </select> <button type="submit" class="primary">Search</button> </div> </div> </form> <hr /> <div class="spinner tertiary"></div> <div class="row" id="movieContainer"></div>
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Belgian railway schedules (advanced)
- Open es6/fetch/irail.html and es6/fetch/irail.js
- For this example we our exact location and two API cals
- Use the Geolocation API to get your exact location
- Grab a list of all Belgian railway stations from https://api.irail.be/stations/?format=json&lang=en (opens new window)
- Grab a timetable from one of your closest railway stations
E.g: the railway station of Geel has anid
ofBE.NMBS.008832433
https://api.irail.be/liveboard/?id=BE.NMBS.008832433&format=json&lang=en (opens new window)
HTML
JavaScript
result
<!DOCTYPE html> <html lang="en"> <head> ... <style> #preloader { display: flex; } #timetable div span:first-child { font-family: monospace; } #timetable div span:nth-child(2) { display: inline-block; font-family: monospace; width: 35px; text-align: center; font-weight: bold; color: darkred; } #timetable div span:nth-child(3) { display: inline-block; width: 30px; text-align: center; margin: 0 0.5rem; background-color: darkslategray; color: white; } </style> </head> <body> ... <div id="preloader"> <div class="spinner tertiary"></div> <p>loading...</p> </div> <div id="buttons"></div> <h3 id="station"></h3> <div id="timetable"></div> ... </body> </html>
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
READING TIPS
- Fetch API@Mozilla (opens new window)
- Fetch API@W3Schools (opens new window)
- Fake REST API's to test with:
WATCHING TIPS