@guildadev/jsonapi-to-model
v1.0.3
Published
The package leverages the best of metaprogramming, allowing direct access to data through an abstract model that represents a database table.
Downloads
8
Readme
Introduction
The package leverages the best of metaprogramming, allowing direct access to data through an abstract model that represents a database table.
Installation
yarn add @guidadev/jsonapi-to-model
or
npm install @guidadev/jsonapi-to-model
Performance
I created a benchmark to compare the performance of deserializing JSON:API data and directly accessing the included data. The results are as follows:
| Benchmark Type | Total Items | Deserialization Time | Total Time | Get Photos in Included | Photos IDs | Included Length | |---------------------|-------------|----------------------|------------|------------------------|------------|-----------------| | Deserialize | 1000 | 70ms | 70ms | 0ms | 10877 | 1000 | | Model | 1000 | 0ms | 0ms | 1ms | 10877 | 1000 |
Why is the model faster? Because we don't need to parse the entire JSON:API payload. We only need to allocate the object, which is faster than parsing the entire JSON:API payload.
Usage
Here's how you can start using @guidadev/jsonapi-to-model in your projects:
// model/User.ts
import { Attribute, BaseEntity } from "@guildadev/jsonapi-to-model";
export class User extends BaseEntity {
@Attribute()
declare name: string;
}
// services/users.ts
export function useUsersQuery() {
return useQuery<User[]>({
queryKey: ["users"],
queryFn: async () => {
const request = await api.get('/user')
const data = request.data
const user = new User(data);
return user;
},
});
}
export function useUserQuery() {
return useQuery<User>({
queryKey: ["user", 1],
queryFn: async () => {
const request = await api.get('/user/1')
const data = request.data
const user = new User(data);
return user;
},
});
}
// Component.tsx
import { useUserQuery } from "@/provider/useUserQuery";
export default function Hello() {
const { data: user, isLoading } = useUserQuery();
if (isLoading) {
return <div>Loading...</div>;
}
if (!user) {
return <div>User not found</div>;
}
return <div>Hello, {user.name} </div>;
}
in tsconfig, inside compilerOptions, you need add:
{
"experimentalDecorators": true,
"useDefineForClassFields": true
}
Check how we are using in React, NextJS and Angular: https://github.com/GuildaDev/jsonapi-to-model-apps-demo
You can also get metas, array of JSON:API, object member metas
Check more on: model-object.test.ts and model-arrays.test.ts
Limitations
Even though esbuild and Vite 5 allow the use of experimentalDecorators (without reflection support), SWC does not support this feature. To work around this limitation in SWC, you can use internal helpers.
See limitations
References:
https://www.typescriptlang.org/docs/handbook/decorators.html