I'm looking for the best practice to do a conversion when my api is sending me a snake case value and my front only accepts pascal case attributes.
Here is my problem :
Front Request
I have an axios request that gets multiple users. Let's say axios.get('/users')
Api answer
My api gives me a list of users :
[{
id: 10
last_name: 'Foo'
first_name: 'Bar'
},{
id: 11
last_name: 'Baz'
first_name: 'Bob'
}]
Typescript User type
Now I have a User type and my typescript only accepts pascal case attributes :
type User = {
id: number,
lastName: string,
firstName: string
}
Typing my axios response
And now I'm passing the received users to an array users
but the error occurs when I want to associate lastName
with last_name
and firstName
with first_name
.
let users: User[] = []
const res = await axios.get('/users')
res.data.forEach((user: User) => {
users.push({
id: user.id,
lastName: user.last_name, // Typescript Error
firstName: user.first_name // Typescript Error
})
}
return users
Do anyone have a solution to this problème ? Do I need to tell my array that the user received by the api is of any
type ? What is the best practice ?
CodePudding user response:
You have two approaches:
Approach 1: Type the response from API differently
Because your response data has different keys, you can't really type it as User
. You should have a separate type for it.
type UserData = {
id: number,
last_name: string,
first_name: string
}
This would, of course, double the maintenance effort whenever you need to change some field's name and is more error-prone. However it is also more flexible.
Approach 2: Convert response's field names before using it.
You can write a small utility that recursively converts field names from snake_case to camelCase. After that, you can type the response correctly as User
. I use this approach personally and it works well, but typing the code is a little tricky. Below is the code I usually use, it might not be perfect and everyone is welcome to give feedback.
import { camelCase } from 'lodash-es';
export type JSONValue =
| string
| number
| boolean
| JSONValue[]
| { [key: string]: JSONValue };
const recursivelyTransformKeys = (obj: JSONValue): JSONValue => {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
if (Array.isArray(obj)) {
return obj.map(recursivelyTransformKeys);
}
const result: JSONValue = {};
Object.entries(obj).forEach(([k, v]) => {
result[camelCase(k)] = recursivelyTransformKeys(v);
});
return result;
};
Then use it in your code like so:
const res = await axios.get('/users')
recursivelyTransformKeys(res.data).forEach((user: User) => {
users.push(user);
}
CodePudding user response:
If you want to use Typescript to resolve above scenario then following way you can achieve it
interface user{
id: number,
lastName: string,
firstName: string
}
interface userResponse{
last_name: string,
first_name: string
}
type User = userResponse | user;
const anExampleVariable: user = {
id: 123,
lastName: "123",
firstName: "12"
}
Another way is to create helper function, then loop through response key and user helper function to transform keys from snack_case to pascalCase
Here is the Helper function
function pascalCase(val){
const ary = val.split("_");
return ary[0] ary[1].charAt(0).toUpperCase() ary[1].slice(1)
}