Making API Calls in a React Native App With fetch and Axios

The very reliable "fetch". Learn the best practices for structuring the app's services and APIs to make them resilient to change.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the The newline Guide to React Native for JavaScript Developers using TypeScript course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to The newline Guide to React Native for JavaScript Developers using TypeScript, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course The newline Guide to React Native for JavaScript Developers using TypeScript
  • [00:00 - 00:08] Making API calls the React Native is quite similar to how we do it in React. And we have all the options available that we have on the web version.

    [00:09 - 00:19] We can do XML HTTP request, the native APIs, or we can also use fetch. And we can also use popular libraries like Exios.

    [00:20 - 00:35] In this example, we are going to use fetch for most of the examples that we are going to see. Before we jump into seeing how to make API calls, there is a particular structure that I recommend using.

    [00:36 - 00:46] If we go to our services folder in the application, we will find another folder that is called core. And this is where I recommend implementing all the low-level APIs.

    [00:47 - 00:56] As in, let's say we want to make a network call. And we want to use XML HTTP request or fetch or Exios or anything for that.

    [00:57 - 01:15] So I would recommend exposing simple GET post and other methods from this particular core service. And doing the actual implementation here, as in if we say that we are writing fetch, we implement the fetch over here and expose only our verbs from here.

    [01:16 - 01:41] Similarly for storage, let's say that we want to use async storage, which is pretty popular in React Native, or we want to store data into a database, or maybe something else, maybe into a network database that I have on AWS, or Firebase, or Firestore, or anywhere. I would recommend that we create some core APIs that handle and wrap these implementations for the rest of the application to use.

    [01:42 - 01:55] So the application can have services like home page service, or product detail service, or a checkout service that allows us to add items to cart. And what it can do is it can simply do a storage.get and set.

    [01:56 - 02:05] And it doesn't need to care about the actual implementation, whether it's being stored in an async storage or in memory or maybe over a network. That is not what the application is concerned about.

    [02:06 - 02:29] And what that also allows us to do is tomorrow if you want to move from an in memory storage or an async storage to a database or a network storage, or maybe we want to implement server-side cart, and we want to move from async storage to storing the cart for logged in user on our server-side. All that can be black-boxed out from a checkout service which simply says "Add to cart".

    [02:30 - 02:34] So basically the cart gets saved. It doesn't need to worry about where it's getting saved.

    [02:35 - 02:41] So we'll follow that structure. And we're going to call that base API.

    [02:42 - 02:53] And what this is going to do is it's going to expose some get post methods. So for example, we're going to use an actual mock product responses so that we can simulate a real implementation.

    [02:54 - 03:00] So we're going to use some mock APIs. And as we see there are certain headers that are always required.

    [03:01 - 03:11] Wherever we try to make the call, if we try to make calls for search result or reviews or details, we need to set some headers and verbs. So we can also do these in our base API implementation.

    [03:12 - 03:25] So we can set these headers right in a method that's called get default headers . And whenever we call this particular verb get or post or the others, they know what headers to set before making the actual call.

    [03:26 - 03:34] That way that complexity is hidden away from the rest of the app. And let's say tomorrow we have a requirement to set some new header or a new context.

    [03:35 - 03:49] Let's say that we have one more header that adds here or we need to change the key or the host for that. The services that we implement, like the checkout service in the app service, they don't need to worry about it. All of this will be taken care of.

    [03:50 - 04:20] Secondly, what this also allows us to do is let's say that we want to use async storage on iOS, but something else on Android, maybe we want to do a database for some reason. Now, if we have a storage service that just exposes different methods, like get item, set item, and remove item or clear all, what we can do is we can implement them over here and say for platform equals to iOS, we can have our iOS specific implementations and for Android and right specific implementations.

    [04:21 - 04:28] So now what the services will do is they simply call storage.get and set. They don't need to worry about platform specific nuances.

    [04:29 - 04:41] So this structure really helps segregate the service implementations to actual consumption and using them. So we'll try to do a carousel and the data for the listings page or the search page.

    [04:42 - 04:50] Using the fetch, we can also use exeos for that. Exeos is a very popular library. It has more than 50,000 GitHub stars.

    [04:51 - 05:02] And apart from other things, it also allows to do is it allows you to cancel a network request. And it also has interceptors as in if you want to intercept the request or the response.

    [05:03 - 05:10] You want to modify the response or the request based on whether it's successful or it's failed. We can do all of that.

    [05:11 - 05:18] If you're interested, you can go and look into this themselves. We'll try and do the most common and the most famous one that we have on the web today and that's fetch.

    [05:19 - 05:26] So what we'll do is we'll implement get and post with that. And we'll try to render our respective pages.

    [05:27 - 05:32] So let me just start with that. First, we'll go to shared and here we have the services.

    [05:33 - 05:38] In services, we have our core and then there's an API. It's an empty file right now. And we also have our storage.

    [05:39 - 05:47] So for storage, what we'll do is we'll implement the async storage. That's one of the upcoming lessons in this particular module.

    [05:48 - 05:53] We'll implement that over there. For this lesson, we'll implement the API, the get and the post.

    [05:54 - 06:16] So let's go ahead and do that. We'll say const API equals let's expose a get method and also a post method.

    [06:17 - 06:24] And what we can do is we're going to use fetch for this. So we'll say return.

    [06:25 - 06:34] Fetch. And we will need our endpoint.

    [06:35 - 06:52] So let's declare that we will have our endpoint and we'll also have our, query params which will probably be an object. So let's declare that as any found out.

    [06:53 - 07:07] So we'll say method get headers. Let's declare that.

    [07:08 - 07:16] Let's declare some default headers. So we'll say const default headers equals.

    [07:17 - 07:29] And we'll say return. We can simply copy these for now.

    [07:30 - 07:42] And over near we'll say we'll pick up from the mark response. That we're using for this application.

    [07:43 - 07:54] What we can also do is we can create a config so that we pull all of this data from that. So in shared services, let's have a new file that's called config.

    [07:55 - 08:27] And what we can do is export default and APIs. So now we can pull that from there.

    [08:28 - 08:52] We'll say import config. From config will say config.api.host and config.api.key.

    [08:53 - 09:02] And now let's call this default headers. Now we have our base get and point set up.

    [09:03 - 09:07] We also need to pass the query parameters. So it will basically be let's say that this is an object.

    [09:08 - 09:16] Then we'll probably need a method to convert that into the query parameter format. So I've already declared a method for that in utils.

    [09:17 - 09:26] So let's use that. So we will say we'll import that and we'll just pass the params to it.

    [09:27 - 09:37] What it will do is it will convert that into the query parameter format and then return it. So we have our base get implementation.

    [09:38 - 10:06] Similarly, we can do for post and instead of get what we'll do is we'll post. Again, we'll have patterns in post the patterns as passed as a body.

    [10:07 - 10:19] And we'll say this and dot stringify and we'll say farems. So that's our base get and post implementations.

    [10:20 - 10:26] We're going to use that from one of the services that we declare under services . So let's do that.

    [10:27 - 10:35] Before we go ahead, we need to export this. We'll say export default API.

    [10:36 - 10:43] Let's go ahead and use this API to implement the search page. Earlier we had built this page where we had these recent searches.

    [10:44 - 10:56] What we'll do here is once we click on any of these recent searches, they'll go to the listings page that we have. And as soon as the listings page loads, we'll make the API call and display the product for that.

    [10:57 - 11:08] If we recall the design for the listings page, we had these product cards that we have already built on the homepage. So we'll reuse this and we'll build this section for now.

    [11:09 - 11:17] So let's go ahead and do that. So before we move ahead, just a little bit about the process that we're going to follow.

    [11:18 - 11:24] We're going to create a new service for this and we can probably call it a search service. We'll create a new one over here.

    [11:25 - 11:34] And what we'll do is we'll call it from our thunk. So we'll create a thunk for search and we'll call it from there.

    [11:35 - 11:40] Now you might be thinking that we could directly call this service from our search page, right? What is the point of calling it from thunk?

    [11:41 - 11:49] But that is not a good idea. Views are supposed to fire an action and they should be black-washed with the actual implementation of the action.

    [11:50 - 12:01] They should just care about getting the data or whatever the action is supposed to return. If the action is making a network call or it's getting the data from an async storage or maybe in memory, that's not the concern of the view.

    [12:02 - 12:12] So if I run action from our view using the action creators, the thunk and then thunk will now be responsible for implementing a business logic for that. In this case, it's quite simple.

    [12:13 - 12:24] It's just going to call the service that we create for search, but it can be more complex. Now let's say that when we load the application and we want the cart information for a particular user, there might be two steps to it.

    [12:25 - 12:29] The first is we get the token for a user from the async storage. So that's one action.

    [12:30 - 12:48] And then the second action is we make call for that user and validate the token and then get back the cart for that user. So instead of adding that business logic to the UI and firing two different actions, what we can do is we can create a thunk and then from thunk we can manage all that.

    [12:49 - 12:56] So that abstracts the implementation out from the UI and UI only gets the cart information that it requires. So let's do that.

    [12:57 - 13:45] Let's create a service. And let's call it search and we'll say search service and let's do and we'll have a search term and what we can do is get and then we will add the endpoint from our config.

    [13:46 - 13:51] So we have this config defined and it has the endpoint for search. So let's use that.

    [13:52 - 14:12] So we'll say APIs. Endpoints.

    [14:13 - 14:36] API is stored endpoint stored search and then we'll add the search term to it. A search term may have space is another special character.

    [14:37 - 14:42] So it's always a good idea to. You are encoded.

    [14:43 - 14:46] We'll say encode you are. And the second one is the param.

    [14:47 - 15:07] So we'll pass the params which is the API key. So we'll say API key.

    [15:08 - 15:13] So that should mostly be it. This get endpoint actually returns a promise of a response.

    [15:14 - 15:34] So what we need to do here is we need to do a dot then and we'll say response. json and we should also add the catch block for errors.

    [15:35 - 15:48] And let's console it from now. But ideally we want to push this to some sort of error monitoring tool like we 'll see a century and we can push it to that.

    [15:49 - 16:09] But for now let's just return a promise and we'll say error. So our search service should be ready now.

    [16:10 - 16:19] Let's now create the tongue for it to call from the UI. We'll go to tongue and let's just copy over the app one.

    [16:20 - 16:55] So we'll say search and let's go to actions and define actions for this. So we might also do search failed.

    [16:56 - 17:30] If the network request fails or we get a bad response from the server side we can declare that and we'll go to the search actions and we'll say and we'll do data. So now we can declare the type for it.

    [17:31 - 17:34] We have the types folder. So let's declare one for search.

    [17:35 - 18:14] So we'll just have a query and we'll see. Let's just type a function.

    [18:15 - 18:17] So that's our action. We have defined it.

    [18:18 - 18:58] Let's go back to thunk for search and we will say search requested and we'll get the action from search and we need to pass the query to it data and then we'll pass the data to it. So that will fire the action for the application saying that we need to initiate a search with this data.

    [18:59 - 19:33] Let's call the service so we'll say we might need to export the search service and we'll say export so we'll say search service dot fetch and this requires the search term which is data. So let's also use async await for this.

    [19:34 - 19:40] So that should give us the result and we will. There are two options here.

    [19:41 - 19:57] One is we return the result from here and that will go back to the UI as it is. One option is that would dispatch some sort of a search succeeded and pass the data to it and then we'll go to a reducer created reducer for search and store the data to the application state.

    [19:58 - 20:10] Now search results are not generally required to be stored to the application state because they're dynamic and they keep changing quite a lot. So we'll not do that and let's go ahead and just return the result.

    [20:11 - 20:21] We'll call this particular action greater from UI and get the result. And the UI will directly get the result once it makes a request for a search.

    [20:22 - 20:33] So now all of that is ready. Let's go ahead and integrate this with UI.

    [20:34 - 20:39] So this is the search page and what we want to do is once we click on any of these we'll go to the listings page. So let's do that.

    [20:40 - 20:46] We have a list and we also have an on click for this. We want to go to the listings page.

    [20:47 - 20:56] So for that we will go to the router and create a new router method for that. Now this is a good practice.

    [20:57 - 21:18] We could either call dot push but what we also wanted to do is we wanted to integrate this button that shows up on the listings page and that requires an additional top bar and then write buttons. So what we can do is we can use the push method but just add that particular option to it.

    [21:19 - 21:35] So what we'll do is we will declare a method for showing the listing screen. Let's call it show listings screen and we'll say push.

    [21:36 - 21:59] The first one is the component ID which we will get from here and then the second is pass props then we need to pass the ID of the screen that we need to show. So we'll say listings and for title what we can do is we can accept the title over here.

    [22:00 - 22:17] So it can be title. So let's go to the website and go to the website.

    [22:18 - 22:26] So we'll go to the website. So we'll go to the website and then we'll go to the website.

    [22:27 - 22:55] So we'll go to the website and then we'll go to the website. Now let's use this.

    [22:56 - 23:19] We'll expose it. Now we can go back here and say router dot show listings screen and we can pass the title.

    [23:20 - 24:00] So we're already getting back the text over here we can pass that as the title and for component ID since we have declared this as a react functional component we get the component ID in the props component ID props dot component ID we are not thinking of passing any other props so we don't need that and let's save it and let's check. Okay so we click speakers we get speakers we click headphones we get headphones .

    [24:01 - 24:48] Next let's go to the listings page and now that we have here what we can do is we can use use effect to make that call to the thunk and call the search service. Let's do that use effect and as you remember from the previous lesson that we should always pass a second parameter to the use effect otherwise this will get executed every time a set state for any variable happens for this particular functional component a good practice would be to always initialize this with an empty array and we can keep adding the variables that we want to watch for.

    [24:49 - 39:15] So let's create that function and we'll say get API data and we need to bind that to our component using match dispatch to props we'll just copy over the type from the home component for props let's just copy over from here and we'll dispatch the action from our thunk and we'll say search this is just a variable name so we can call it anything that we want so we'll say string and we'll say that dispatch that action creator which is called search requested and it needs a type of search state which is query so now it should be available to us in the props let's include that before that let's also move this out index and that should do it and we'll say search string turner and it returns a promise we can also put the search response over here because it's going to respond with that so let's save it it should now be available in our props so we'll say search and we need to pass the query parameter how we can do that is as we saw in the screens lesson earlier that we can pass data from screen to screen using past props let 's go to component and search and we'll use the past props parameters we'll say past props and we'll say query and the query can be the text that we are using now we'll also have the text available as props let's call it query and string and we'll get that so let's just pass that over we'll get the response over here which is of type search response let's do async counts reserved equals await and we can just do set state on that so for that we need to declare a state variable for this functional component so we'll say result set result equals react dot use state we'll use the use state hook and initially we can just pass null to it we don't have anything to initialize this with and we'll say okay let's change this to response and we'll say set result result okay that should give us the data and next what we can do is let's use the data so we'll say result and result dot results so it's giving an error because we have not declared a type for it let's declare a type okay so we need to do that here so we'll say search response which is of type results and an array and it doesn't allow a null so okay we need to do this result and an empty array so what we'll do is we'll just destructure that result results and we can just say results dot length initially it will be zero so if it's greater than zero we can use that so results dot length is greater than zero we 'll just iterate over it and display the product display module so right now this particular module is not dynamic so what we're going to see is the same product but should at least show up the number of times that we have result at is around 20 let's save that and okay we also need to call this so we'll save that and this should be response so we'll save that and let's also add result as watcher so okay that should add in the product display as many number of times okay it's displaying the products but the view is not scrolled and just copy what this style for scroll view and we will say scroll view save it and that should work next let's do two things one is we'll make the product display dynamic and let's also try to render these products side by side so for that what we will do is we'll pass the style to the scroll view itself now there is an attribute that's called content container style and we'll use that we'll say global dot layout dot will declare a style for it so we'll go to layout and we'll say listing and we can say flex direction row and flex wrap as wrap and we'll also do justify content as space between let's save that and we have our listings so once we save that we get the product as side by side let's also remove the text and the button that we don't require anymore so so that looks like how we want to display this right next let's also make the product display dynamic if you look at the search response what we have is we have the name that we can use for title and we can use image for image price for price and we don't seem to have anything for subtitle so we'll let be for now let's say title price and image and let's also pull that from props title price image and let's do one thing let's not remove the default values the reason for that is we have not made any API calls on the homepage so this will stop working what we can do is we can just say if you're getting a title we'll display it otherwise display a default value and we'll remove this once we integrate the castle to any PI so we'll say title and we can do price okay we need to format price so we'll say dollar price if it comes then show this otherwise show a default value and for URL image URL and let's save that and let's also pass that as title and price and image URL product and we should have product dot name product dot price product dot image let's check okay this will be a number so let's save that and now if we try again okay the product names are quite long let's trim them so we'll do substring and that's much better so we mostly have our listings page setup so to recap what we did was we created a core for APIs and we abstracted out the implementation so we are using fetch right now but let's say that we decide to use XCOS going forward so we don't have to change anything in the search service because this is only doing an API.get all we need to do is change the core implementation and the rest of the services can remain agnostic to it. Similarly going forward we'll also do this for storage so we'll implement dacing storage and we'll use that to store data locally into the application and expose that as a common storage API so the services don't need to worry about the actual implementation of storage from there what we did was we created a thunk for our search and from thunk we returned the result now in a lot of cases we might not return the result and we might want to save it to the state so for that what we can do is something like this so we'll say search successful and we'll create a reducer for this and pass the data to it and in the reducer we'll map the data to a store for search though in this case what we want is we don't want to store the search results in the application state so we are simply returning to the view and if you go back to the view what we have done is we have used a use effect and we have called that thunk from here so the view is calling an action which basically says search initiated and it just passes the query parameter to it and the rest is handled by the action creator and the services so apart from that we can also use exeos and there's a sample implementation over here it also supports interceptors if we have a use case for that though which works out great in most of the use cases and next as an exercise we can try integrating the categories to the same search implementation we can reuse the same service but i would recommend that we implement its own thunk unless we think that both are exactly the same use cases so i'll do that and push it to the boilerplate repo that's all for this lesson and i'll see you in the next one