Fetch Requests
Fetch requests are a way to send HTTP requests to a server directly from a page using JavaScript. The advantage of using fetch requests over, say, reloading the page are that
The contents of the page do not need to be reloaded each time the request is made
The request takes a little less time to get processed compared to sending server-to-server requests from the backend.
Allows content to be loaded "optionally" - content is not loaded on the page until it is specifically requested by the user, so pages have less content and are rendered faster.
Syntax
Fetch requests follow this syntax:
resource
is the server (or resource) that the request is being sent to. It is a string with the URL.options
contain some custom settings for the request. More details later
They return a "Promise" - in other words, they return an asynchronous wrapper for the response from the server.
For those of you who have taken CS2030/S, Promises in JavaScript are like CompletableFutures in Java.
This promise can be processed using the .then
method, which takes in a unary function. This function is applied on the response recieved from the server.
The response
The response from a fetch request is a JSON object with parameters like status
and protocol
and body
. Of these, the status
and body
parameters are the most useful for now.
response.status
is an integer representing the HTTP Response Code returned by the server. The full list of response code can be found here, but a few common ones are below:
200 OK
- all good404 NOT FOUND
- the url/resource was not found on the server side500 Internal Server Error
- the server ran into an error when trying to process the request
response.body
is an encoded object that contains the body of the response. Note that failed requests have null
as the value for the body
property for their response objects. To decode the body into readable JSON that can be processed by your JS code, use the method response.json()
.
You could imagine using the status
property in this way:
This status-checking and body-retrieval is often chained into 2 different promises using two sequential then
s:
Let's walk through it step by step:
fetch("somedomain.com/some-route/", someData)
- this line performs the fetch request and returns the response wrapped in a promise.then(response => response.status === 200 ? response.json() : response.status)
- here, we check the response status code to see if the request was successful.If the response was successful (i.e.
response.status === 200
) then we return the body of the response usingresponse.json()
If the response was not successful, we return the status code of the response so it can be shown to the user
.then(data => {...})
- this section of the code takes the data returned after processing the responseIf the data returned is a number (i.e.
typeof(data) === "number"
) then this means that the response status code was returned by the previous function, so there was an error, so we tell the user as suchOtherwise process the data as normal
Note that you may want to add more intermediary conditions and process different response codes differently, but the general form of a fetch request is as above.
The options
Note that the fetch
function takes in two parameters: the resource
, and the options
.
options
is a JSON object that contains any custom settings that you may want to apply to the request. This includes header data, type of content being sent (if any), the content itself, and others. If any settings are ommitted, then the browser plugs in the default values for each setting. Below is an example of the options object, filled with default values for each setting (not all possible settings are shown).
Let's look at each setting:
method
- this setting specifies the request method. There are 4 commonly used methods(GET
,POST
,PUT
andDELETE
), and each are used in different situations. More details heremode
- what resource sharing mode should be allowed."cors"
stands for "Cross-Origin Resource Sharing", and this mode allows sharing resources across origins. The other options are"no-cors"
and"same-origin"
. More details herecache
- how the request interacts with the browser's cache. Some different options are "no-cache", "no-store", "reload", and "only-if-cached". These options are explained herecredentials
- this specifies whether or not the user should send/receive cookies from the resource. The two other options are"omit"
(never send/receive cookies) and"include"
(always send/receive cookies). More details hereredirect
- this specifies how to handle if the resource redirects our request elsewhere. Some other options are"error"
and"manual"
. More details hereheaders
- this is a JSON object that contains the headers for the request. The sample shows two header settings:"Content-Type"
- this header specifies the type of content being requested. It is in the format"type/subtype"
and some examples are"image/png"
(a png image),"text/plain"
(plain text), or"multipart/form-data"
(multiple parts of form data). The full list of options can be found here."Access-Control-Allow-Origin"
- this header indicates whether the response can be shared with requesting code from the given origin. This could be"*"
, so all origins can have access to the response, or"<origin>"
where<origin>
is a domain/IP address. More details here
There are many more headers that can be assigned, and they are all listed here.
body
- this setting specifies the body of the request (i.e. some data that needs to be processed by the resource server). Note that this must be a string;JSON.stringify
allows us to represent a JSON object with the request body as a string. Note also that abody
CANNOT be present for aGET
request.
The Mozilla Developer Network web docs are a very very useful resource for understanding HTTP requests and responses, as well as frontend web development with JavaScript.
Next steps
Next, we'll write our own fetch request to the NUSMods API.
Last updated