๐Reaching out to the Web
Working with fetch() and Axios to work with APIs.
Last updated
Working with fetch() and Axios to work with APIs.
Last updated
Typically, in a standalone React app, when we request data from the server, we do not get an HTML page from the server, we get JSON data back from it, which we in turn render on the web app.
Axios
This is a Promise
based XMLHTTPRequest()
wrapper, which we can include in our project using the following command:
Let's create an HTTP GET request to fetch data from the server. Here, we will be using a dummy API from JSONPlaceholder, where we access the /posts/
route on this website to access all the posts available on this dummy JSON data website.
We will access the posts from this URL: https://jsonplaceholder.typicode.com/posts/
During component creation, Ii the lifecycle hooks for class based components, we will access the server in the componentDidMount()
lifecycle hook, because this is where we can cause side effect, like making HTTP requests.
We also need to import axios
.
We can see in the console, the response object that is returned by the URL. We can now render this into out Post component, with limiting the number of posts from the data, and adding our own attribute to the data as well (appending data to response data). We'll also add a clickEventHandler
to select a post from the displayed 4 posts from the server, and show the title and content on the FullPost
component.
Let's see our Post
component:
In our FullPost
component, we need to display the selected post based on the selectedPostId
:
NOTE: Since we are updating the FullPost
component upon a click event from the Post
component, we need to fetch the post data inside a lifecycle hook function where we can perform side effects like accessing the server. So the HTTP request to the server will come from the componentDidUpdate()
lifecycle hook during the component update lifecycle.
Here, we will have to fetch data on update, without creating infinite loops! If we were to check the network tab when we click a post, there are continuous requests being made to the server since we are updating or setting the state inside the componentDidUpdate
lifecycle hook. To overcome this, we need to add a condition to only fetch data and update the state when the loadedPost
is null or when the id
of the displayed post is not equal to the id
of the post that is selected. We would also need a check if the this.props.id
is valid, i.e, if a post is even selected firstly!
Now, we need to conditionally render the post data that is selected.
With this, the requests to the server are limited, and the post is displayed only when the post is not already loaded, or when the id
of the displayed and selected posts do not match. The highlighted part in the above code, is a delete
button, which will help us to delete data from the dummy server, let see how we can do that.
In the above code, we have added a button delete
to delete the post based on the FullPost
that is displayed. So we need to send a DELETE
request to the server to remove the entry from the back-end. Since we are working with a dummy back-end server, we will only console.log
the deleted request.
To POST data to the server, we can send a POST request to the URL with axios. Let's POST some data to the server in the NewPost
component:
We add the postDataHandler
to the Add Post
button to POST the data to the dummy server, and log the result to the console. Since this is a dummy POST entry to the server, we can only log the response.
After the then()
in the axios chain, we can add another method to this chain, called catch()
, to catch errors that may be present while fetching or posting or deleting or performing any other activity on the server side through the URL.
Let's see how it would work if we had an error in out GET
request:
We can also not log the error, and use the catch block to show something on the webpage in case there is an error.
Axios has interceptors, to execute code globally, or usually to handle errors on a global level, rather than a local level as we saw above with the catch
method chaining. This is the place where we add authentication headers and such other things in a web application.
We will add the interceptors
in the index.js
file,
In the request
method of interceptors, we need to always return the request data, otherwise we are blocking the request! In case there is an error, we need to reject to Promise
with that error, as shown above in the code snippet.
You learned how to add an interceptor, getting rid of one is also easy. Simply store the reference to the interceptor in a variable and call eject
with that reference as an argument, to remove it (more info: https://github.com/axios/axios#interceptors):
We will use the defaults
object to set up default config for all the requests being sent out. There we can use a baseURL
property to set the base URL. The other paths where we use axios.get()
or axios.post()
or axios.delete()
will now have the baseURL
appended to their paths.
We can also do this with headers
as well.
So now when we POST some data to our dummy server, we can see in the logged response object, the above headers.
In the above screenshot, we can see under headers
, "Authorization: AUTH TOKEN" and "Content-Type: application/json"
Instances
We can use Axios Instances in places where we want to override or use our own configurations instead of the default global ones setup in the index.js
file.
To create an Axios Instance, we will create a new file called Axios.js
in the src/
folder:
Now, we can use this in any of our components, say Blog.js
:
We can also define the interceptors for our instances as well.
Using Instances
allows us to have the flexibility to control, in detail, in which part of the app we want to use the default settings.
For more info on Axios
, check out their official docs.
Fetch
APIThis is a feature built into the browser for fetching data from an API. It is an alternative to Axios
We can avoid the second parameter, which is the object with key-value pairs, that tells what config is needed to fetch data from the server. The default method
if we do not provide this second parameter, is GET
, to get data from the server. In case we need to send data to the server, we will use the second parameter, with the key-value pair of method: 'POST'
. The JSON
object that we need to POST to the server is sent in the body
key, with the JSON
object as the value.
Fetch returns a promise, that needs to be handled appropriately. This is an asynchronous process, and hence we have promises.
So whenever we get a response, we have a then()
to handle the response. To handle errors, we use the catch()
.
Since the fetch()
works with promises, we have to chain the then()
blocks after it. This then()
block chaining would become a really long chain if we have a lot of then()
blocks. To avoid then block chaining, we have something called async
and await
.
async
& await
We add the async
keyword in front of the function where we perform a side-effect, like fetching data from a server, which is an asynchronous task. Then, we add the await
keyword in front of the actual method that performs the side-effect, i.e, where we call the fetch()
function to fetch data from the server.
The async
and await
work in the exact way the fetch()
works with the then()
method calls. This would simplify our code to a good extent.