Data Serialization
One problem with passing Prisma requests and responses across the network is that the data is not always serializable. The following Prisma types are problematic:
Date
: Javascript'sDate
object is serializable, but its type is lostBytes
: not serializableBigInt
: not serializableDecimal
: not serializable
ZenStack solves this problem by using superjson to deserialize input and serialize output. Since data is still JSON-serializable most of the time, ZenStack adopts superjson in a non-intrusive way. The serialized data is directly put inside the request or response data. When there is extra serialization information (superjson generates it when it encounters data that's not JSON-serializable), it's put inside the meta
field in the request or response.
The benefit of this design is that if the data is fully JSON-serializable (not involving the types mentioned above), the wire format is just plain JSON serialization without any pollution.
You can find more details about serialization in the RPC API Handler and RESTful API Handler documentation.
🛠️ Observing Serialization Behavior
To illustrate this, let's try a few requests to observe the serialization behavior.
Make the following request to find the first List
with {"select":{"id":true,"title":true}}
:
curl "http://localhost:3000/api/rpc/list/findFirst?q=%7B%22select%22%3A%7B%22id%22%3Atrue%2C%22title%22%3Atrue%7D%7D" -H "x-user-id: 1"
You should get a simple response. Since the result data is fully JSON-serializable, the response has no extra serialization metadata.
{
"data": {
"id":1,
"title":"Grocery"
}
}
Now, if we send a different request and ask for the full List
object
curl "http://localhost:3000/api/rpc/list/findFirst" -H "x-user-id: 1"
We get back a richer response. The createdAt
and updatedAt
fields are not directly JSON-serializable, and the information contained in the meta.serialization
field is generated by superjson to facilitate deserialization.
{
"data" : {
"createdAt" : "2023-11-08T04:38:53.385Z",
"id" : 1,
"ownerId" : 1,
"private" : false,
"spaceId" : 1,
"title" : "Grocery",
"updatedAt" : "2023-11-09T04:52:57.987Z"
},
"meta" : {
"serialization" : {
"values" : {
"createdAt" : [ "Date" ],
"updatedAt" : [ "Date" ]
}
}
}
}
The API consumer should pass the data and the serialization metadata to the superjson API to get back data with full fidelity. The following code shows how to deserialize and restore the proper Date
type for the createdAt
and updatedAt
fields.
import SuperJSON from 'superjson';
SuperJSON.deserialize({
json: {
"createdAt" : "2023-11-08T04:38:53.385Z",
"id" : 1,
"ownerId" : 1,
"private" : false,
"spaceId" : 1,
"title" : "Grocery",
"updatedAt" : "2023-11-09T04:52:57.987Z"
},
meta: {
"values" : {
"createdAt" : [ "Date" ],
"updatedAt" : [ "Date" ]
}
}
});
{
createdAt: 2023-11-08T04:38:53.385Z,
id: 1,
ownerId: 1,
private: false,
spaceId: 1,
title: 'Grocery',
updatedAt: 2023-11-09T04:52:57.987Z
}