When building applications with Ionic, we will often need to fetch some data over the network - whether that is locally to pull in data from a JSON file, or through the Internet to load data supplied by some API.
If you’ve been around for a while you might recall using an XMLHttpRequest()
to perform HTTP requests with JavaScript - this wasn’t/isn’t a particularly nice way to perform requests, and many people would use additional libraries to help simplify the process of sending HTTP requests.
Browser APIs have come a long way over the years, and now we have the Fetch API that is built in to modern browsers by default available to us. This API makes it much simpler to execute HTTP requests without the use of an external library. It performs a similar role to the standard XMLHttpRequest
, but it uses Promises
and is much simpler to use. A simple request using the Fetch API might look something like this:
let response = await fetch('https://someapi.com/data');
let json = await response.json();
We can run the code above in our Ionic applications with no need to install any 3rd party libraries. In this tutorial, we are going to walk through the basics of using the Fetch API.
This tutorial has an intended audience of Ionic/StencilJS developers, since using the Fetch API could be considered the default method for running HTTP requests in that context. If you are using Ionic/Angular, for example, you would be more likely to use Angular’s HttpClient. However, the Fetch API is just a generic browser API that can be used anywhere.
NOTE: If you are interested in using Redux in your Ionic/StencilJS applications, I already have a much more advanced tutorial for loading data with the Fetch API and Redux here: State Management with Redux in Ionic & StencilJS: Loading Data.
GET Requests
We are going to discuss some basic examples of using the Fetch API. Keep in mind that we are just going to display the basic request here, but error handling is also an important topic that we will cover in the last section of this tutorial.
To execute a GET
request with the Fetch API, we would do the following:
let response = await fetch('https://someapi.com/data');
let json = await response.json();
We supply the URL that we want to fetch the data from to the fetch
method. This will return a Promise with the result, so we await
it (if you prefer, you could also use the standard Promise syntax with .then()
). Once the Promise resolves, we can then access the data returned through the json()
method.
POST Requests
Running GET
requests are usually a bit easier than POST
requests, because we typically need to send a bit of extra information with a POST
request. We need to send the data itself, as well as any additional headers that might need to be set.
This example is a little bit more complex, but still quite manageable:
let data = {
comment: 'hello',
author: 'josh',
};
let response = await fetch('https://someapi.com/comments', {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
});
let json = await response.json();
We have defined some data
that we want to send along to someapi.com
. Now instead of just supplying the URL to fetch
, we supply an Object
as a second parameter. This object contains all of the extra information we need.
We use this object to set the method
to POST
, we add the data we want to send to body
as a JSON string, and then we set the appropriate Content-Type
header (which is usually going to be application/json
). Aside from that, the rest is the same. We just await
the fetch and the json()
method.
Handling Errors
One perhaps awkward aspect of the Fetch API is that it will not cause a Promise to reject in the case of an HTTP error. This means that even if there is some kind of server error like a 500 - Internal Server Error
the request will still be considered to have executed successfully. A request was made to the server, and a response was received back from the server - technically, you could consider that a “success” even if the response was an error.
That means that if we were simply to wrap our code in a try/catch
block (as we might usually do to handle errors), it won’t trigger the catch
block under all circumstances:
try {
let response = await fetch('https://someapi.com/data');
let json = await response.json();
} catch (err) {
console.log(err);
}
What will happen is that we will receive the response back successfully through the resolved Promise, but the ok
status will be false
if a server error occurred. In the context of our application, we would probably consider a server error to be undesirable behaviour and we would want to trigger some kind of error handling. To handle this situation, we will just need to add a little more logic to our request:
try {
let response = await fetch('https://someapi.com/data');
if (!response.ok) {
throw new Error(response.statusText);
}
let json = await response.json();
} catch (err) {
console.log(err);
}
Now we check the response for the ok
status, and if it is not true
we throw
an error. Since this is inside of the try
block, if we throw an error it will cause it to fail and trigger the catch
, which will result in the error being logged out in this case.
Rather than manually writing this code for every request, you might prefer to set up a little helper function to help handle errors, e.g:
try {
let response = await fetch('https://someapi.com/data');
handleErrors(response);
let json = await response.json();
} catch (err) {
console.log(err);
}
In this case, we can just pass the response to a handleErrors
method that we have defined, and then throw an error in that method if necessary.
Summary
There are many approaches we can take to performing HTTP requests in our Ionic applications, and using an additional library to handle those requests is absolutely fine. In the case of Ionic/Angular, it even makes more sense to use the default HttpClient
that is included since. However, it is nice that we now have a default browser API that is simple enough to use out of the box to perform HTTP requests without requiring any additional libraries.
If you are building Ionic/StencilJS applications, then you might also be interested in combining this concept of using the Fetch API with a service to handle performing those requests for you. If you are interested in a more advanced data loading implementation with Redux, remember to check out State Management with Redux in Ionic & StencilJS: Loading Data.