Request management made easy with @zup-next libraries for react: Part 1.

Tiago Peres França
6 min readMay 28, 2019

--

Motivation

We, at Zup IT, usually use a set of utilities when dealing with request management in react. We recently decided to share them with the community through two different repositories: redux-resource and redux-action-cache. In this article we’re going to talk about the first one, which is responsible for creating almost everything we need to control our requests through the redux actions and state.

Let’s face it, creating action types, action creators, reducers and sagas for every request is boring. It takes time and sometimes it gets hard to maintain. If we are using REST services, every GET, PUT, POST and DELETE is pretty much the same thing. Why are we recreating the code every time we need to call a new service? What if we also treat our requests as REST resources in the front end, can’t we then use the same treatment for every request and avoid code repetition? This is exactly what our redux-resource library intends to do!

An application using our lib

This article presents a simple application created with redux-resource. The application is an online movie store that allows the user to check their current balance, see a catalog of movies and place orders. The focus here will be on how to make the requests, so we won’t talk much about styles or other react components.

The demo project with the full code can be found here. You can follow the instructions in the readme of the repository to get it running. The following images illustrates how the application works:

Screen 1 (Home)

In the first screen, the user checks the balance and the catalog of movies available for purchasing.

Screen 2 (Movie details)

The second screen shows the details of the movie chosen in the previous screen.

Screen 3 (Payment)

The third and final screen is responsible for paying and placing an order.

In the first part of this series of articles, we’ll use the Screen 1 and Screen 2 to show the basic use of the library. In the second part, we’ll implement the third screen, enabling the user to pay for an order. And in the third and final part, we are going to address the problem of making multiple requests to the same url, introducing the library redux-action-cache.

Writing the application

The REST API we’re using to build this application offers the following services:

  • GET /profile: returns the user profile
  • PUT /profile: updates the profile with the object passed in the payload
  • GET /catalog: get the list of movies available
  • GET /wallet: get an object with two properties: balance and cards. “Balance” is a number representing the user’s balance and “cards” is a list of credit cards.
  • POST /wallet: adds a new credit card to the wallet
  • DELETE /wallet: removes a credit card from the wallet
  • POST /order: creates an order

Attention: although http requests can be GET, POST, PUT or DELETE, the operations defined in redux-resource are load, create, update and remove.

We can identify three resources in the first two screens: the user profile, the balance (wallet) and the movie catalog. The first thing we must do is to create the API functions. We recommend using axios for this.

Now that our API interface is set up, we can create the resources:

It’s as simple as that! Every resource can have a load, update, create or remove operation. In this example, we used the operations update profile, create wallet and remove wallet just to illustrate how they could be used, we won’t call them in our demo project.

The function createResource returns an object with the keys:

  • types: the action types (strings)
  • actions: the action creators (functions that create actions)
  • reducers: the reducers to input to redux
  • sagas: the sagas to input to redux-saga

We use the return value of createResource to create our store and dispatch actions. The following code shows how to create the redux store with the resources we created.

Above, combineReducers is a typical function of redux, while createEffects is a utility function of our library responsible for creating the saga effects, it takes an object where each key is an action type and each value a generator function. For more details on createEffects, please, read our documentation.

Now that we have set up the resources and the store, we can start using them! We divided the Screen 1 and Screen 2 into three containers:

  • Header: responsible for the header, shared by all screens
  • Home: responsible for the content of the Screen 1
  • Movie: responsible for the content of the Screen 2

Below, we present the code for the Header container:

Inside the componentDidMount part of the react cycle, we dispatch the load operation for the resources “profile” and “wallet”. In the render function we check the status of our resources and, based on them, we decide what to show. isPristine, isLoading and hasLoadError are helper functions provided by our library, but if you don’t like them, you could check the status directly:

We have four possible status for any resource operation, they are: “pristine”, “pending”, “success” and “error”. We first check for “pristine” because one render is done before componentDidMount is run and we don’t want to render anything before dispatching the actions to load the resources.

The responses for our requests will be returned in the field “data” of the resources. When defining the API (first code presented in this article), we told axios to return only the payload as the response, so, in our case, “data” will always contain the payload of the responses returned from the server.

We can use the same idea to build all other containers. Below we show the code for the Home container.

And the Movie container:

In the container Movie.js, we are not interested in the entire catalog, but only in the movie with id equal to the URL parameter. So we select the movie we want from the catalog using findMovieById. In real world applications you’ll want to use reselect to memoize the movie, since running a findBy inside the render method can be expensive.

Nice! We created three of our four containers already! In this part we were able to implement most of the application using three different requests without writing a single action, reducer or saga! It might not look like much in this simple application, but it saves a lot of time and code in real world apps! Furthermore, we created a very well defined pattern of how to write our interactions with an API, which helps us a lot in maintenance!

In the next part (Part 2), we’ll implement the third screen: the payment interface. For this, we’ll use the operation “create” and some other actions to control its behavior. See you there!

Interested in hooks, typescript and cache? The project demo-typescript, in our repository of demos, implements this same project using typescript instead of javascript. The project demo-hooks, besides using typescript, uses hooks and also sets up an intelligent cache system for the application (spoiler alert: hooks rocks!). About caching, we are still going to talk about it in the third and final part of this series of articles, wait for it!

You could also have noticed the static nature of the resources we created. If we call the load operation of a resource twice, for instance, the current content would get replaced by the new one. This behavior works very well in most of the cases, but what if we wanted to fetch two movies (through a URL like “/movies/{id}”) and show them side-by-side? The library redux-resource also provides the function createDynamicResource for these cases. If you need to use it, take a look at our documentation and the demo demo-dynamic-resource.

I’d like to thank my colleagues Isac e Raphael de Souza for co-authoring the library and revising this article.

--

--