#Type-safety for dates when returning DB entries as JSON

11 messages · Page 1 of 1 (latest)

winged juniper
#

I used to use Prisma in server components where I don't need to do serialization.

Now I need to return DB entries from an API route handler in JSON form.

This means, the Date type of the Prisma model is not correct on the client anymore. JSONification turns the Date into a string.

What's the correct way to handle this on the client so I have type-safety?

const posts = await prisma.post.findMany({
  include: getPostWithReplyToInclude(user?.id),
  orderBy: {
    createdAt: "desc",
  },
  take: pageSize + 1,
  cursor: cursor ? { id: cursor } : undefined,
});

const nextCursor = posts.length > pageSize ? posts[pageSize].id : null;

const responseBody: PostsPage = {
  posts: posts.slice(0, pageSize),
  nextCursor,
};

return Response.json(responseBody);
visual cipherBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> ✅ Mark Solution

winged juniper
#

Type-safety for dates when returning DB entries as JSON

sick flame
#

@winged juniper Assuming that Response.json uses JSON.stringify somewhere under the hood, the Date object will get converted into an ISO formatted string.

On the client, you will need to manually do the reverse. Assuming you use JS, intercept the response and update the specific fields you know to be returning timestamps using the Date constructor.

Also consider whether you really need a Date type on the client. date-fns for example (which I use to format dates nicely and get relative distance, eg. "a few minutes ago") accepts either Date objects or strings, which get automatically parsed.

winged juniper
visual quiver
winged juniper
winged juniper
#

I don't want to litter my components with Jsonify<T>

visual quiver
#

Forgive me because I'm still a bit of a frontend newbie 😅

But to me it seems that on the frontend you could do make a type like the following:

(horrible pseudocode incoming)

import { Prisma } from '@prisma/client'

export type PrismaUser = Omit<Prisma.UserGetPayload, 'createdAt'> & { 'createdAt': string }

would that work?

winged juniper
#

I think so. But I decided to create a wrapper around fetch that parses timestamp strings back to Date objects:

import ky from "ky";

const kyInstance = ky.create({
  parseJson: (text) =>
    JSON.parse(text, (key, value) => {
      if (key.endsWith("At")) return new Date(value);
      return value;
    }),
});

export default kyInstance;