This is my note when I learned how to customize raw API responses with the transformResponse.
According to the official document,
Individual endpoints on createApi accept a transformResponse property which allows manipulation of the data returned by a query or mutation before it hits the cache.
FYI: RTK Query has a feature for managing cached data that saves the data in the Redux store as a cache for reuse when another request is made for the same data.
transformResponse
By default, transformResponse receives a baseQuery return value (, and potentially meta and arg) from baseQuery and returns it unchanged without any manipulation
function defaultTransformResponse(
baseQueryReturnValue: unknown,
meta: unknown,
arg: unknown
) {
return baseQueryReturnValue
}
ref: https://redux-toolkit.js.org/rtk-query/usage/customizing-queries#customizing-query-responses-with-transformresponse
You can modify the baseQuery return value within the transformResponse function.
Code Example
Here is my code example:
1) Retrieve Star Wars characters data from the following URL: https://akabab.github.io/starwars-api/api
2) Clean up unnecessary data, add a label of either “ABY” or “BBY” for the year information, and include Body Mass Index (BMI) data.
3) Change the data structure
// from
[
{
id: 1,
name: Name,
species: SpeciesName
year: -2,
...
},
{
...
},
...
]
// to
{
SpeciesName:[
{
id: 1,
name: Name,
species: SpeciesName,
year: "2 BBY"
...
},
...
],
[
...
],
...
}
API slice
You will use the transformResponse property in the API slice.
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import {
RowCharacter,
CategorizedCharacters,
ModifiedCharacter
} from "./starWars-types";
import { modifyRowCharacters, categorizeCharacters } from "./starWars-utils";
export const starWarsApi = createApi({
reducerPath: "starWarsApi",
baseQuery: fetchBaseQuery({
baseUrl: "https://akabab.github.io/starwars-api/api/"
}),
endpoints: (builder) => ({
getCharacters: builder.query<CategorizedCharacters, undefined>({
query: () => "all.json",
transformResponse: (response: RowCharacter[]): CategorizedCharacters => {
if (response.length === 0) return {};
const modifiedCharacters = modifyRowCharacters(response);
const categorizedCharacters = categorizeCharacters(modifiedCharacters);
return { all: modifiedCharacters, ...categorizedCharacters };
}
})
})
});
modifyRowCharacters
This code corresponds to the second process the above.
export const modifyRowCharacters = (
characters: RowCharacter[]
): ModifiedCharacter[] => {
const modifiedCharacters: ModifiedCharacter[] = [];
const calcBMI = (height: number, mass: number): number =>
+(mass / Math.pow(height, 2)).toFixed(2);
const convertToStarWarsDating = (year: number) =>
year > 0 ? `${year} ABY` : `${Math.abs(year)} BBY`;
for (const character of characters) {
const bmi =
character.height && character.mass
? calcBMI(character.height, character.mass)
: undefined;
modifiedCharacters.push({
id: character.id,
name: character.name,
image: character.image,
gender: character.gender,
species: character.species,
...(bmi && {
bmi,
height: character.height,
mass: character.mass
}),
...(character.homeworld && { homeworld: character.homeworld }),
...(character.born && { born: convertToStarWarsDating(+character.born) }),
...(character.died && { died: convertToStarWarsDating(+character.died) })
});
}
return modifiedCharacters;
};
categorizeCharacters
This code is for the third process.
export const categorizeCharacters = (
characters: ModifiedCharacter[]
): CategorizedCharacters => {
const categorizedCharacters = characters.reduce(
(acc: CategorizedCharacters, character: ModifiedCharacter) => {
if (acc[character.species]) {
acc[character.species].push(character);
return acc;
}
acc[character.species] = [character];
return acc;
},
{}
);
return categorizedCharacters;
};
Thank you for reading :)
The entire code is available here.
The original article is here
Top comments (0)