Using Mappers to Organize Your Data
Improve the organization of your components
At some point during the development of your project, you might have needed to develop a feature that consumed data from an external source. You had no idea, however, about the shape of the data. All you had is a wireframe or a mock of the screen.
Undoubtedly, you’ve called your backend co-worker to ask for a sample of the API response so you can identify the elements you need. But you haven’t gotten it right away, so you turned your brain into the “I need this, how can I guess it?” mode.
In such a situation, you need to be able to fake out an API response using the wireframe as a reference. But what happens when you finally obtain the real API response from your backend co-worker? There would be a lot of places to replace the fake API response, including components and tests. How can you minimize the number of changes and benefit the application code as a side-effect?
The Problem
It's important to make your components independent of the API response format. — Talysson de Oliveira
Disclaimer: It might seem the Mapper is a design pattern, but it isn’t. A design pattern could probably be used to solve the same problem but not as easily as the Mapper does.
In the test code below, you can see the issue where we couple our components to the API response consumed by them:
Instead of that, you can use a mapper to protect your code from changes to the data shape and allow your team to respond faster to changing requirements.
The Solution: Mapper
The mapper is really simple. It consists in a schema with the structure of the data in the form that you prefer, and the moment you receive a response from the API, the data will be tailored to your component’s input format. All the mapper does is map input to output:
Creating mappers can come in handy when you have to deal with data from external sources but you have no control over the data. Good use cases include Unit Testing and Components (not only React Components).
Using Mapper on Components
Imagine a scenario where you have several components developed by different people from your team. Each one decides to name the props as they wish, and you end up with a few components having props named equal to the API response.
Without the application of the mapper technique, any change to the source and structure of the data returned by the API would have greatly increased its complexity. You would need to review various components and unit tests. Therefore, a mapper also helps standardize the input format required by your components.
Here are two examples of how this technique would improve your code without the need to perform a lot of data manipulation. Imagine that the following userMapper
variable is the result of applying the API response to a mapper function (we’ll show the mapper function in the next section):
As you can see, the mapper acts as a filter on the API response, which can then be applied to both User
components uniformly.
Using Mapper on Unit Tests
In the next example, you have not only unit tests, but a complete example of how the mapper should work. Besides being used within your code, the mapper can also be used by your unit tests.
In the following test sample, we are handing a stubbed API_RESPONSE
to apiResponseMapper
— which is our mapper function — before passing the result on to the UserProfile
and UserRating
components.
Note that the Mapper entry point, userDataMapper
, takes two parameters: data
and origin
.
data
is the API response;origin
allows us to associate mappers with different data sources. In our example, we are using the“API”
data source, which is handled by theapiResponseMapper
function. Of course, we can specify mappers for other data sources on an as-needed basis.
Conclusion
The mapper is not a silver bullet, but you can certainly take advantage of it — whether in small projects or in projects where you have many Data Sources or a large team.
This technique will certainly help to keep your code clean, well organized and drier, thus avoiding a mess of names, props, mocks, issues, and bugs caused due to changes in the third party API.
True Story: I would have really liked to have this concept in my head months ago before I started to work on my new project. That would have saved many mistakes and the migration to a new API.