connectrpc / connect-query-es

TypeScript-first expansion pack for TanStack Query that gives you Protobuf superpowers.
https://connectrpc.com/docs/web/query/getting-started
Apache License 2.0
218 stars 14 forks source link

Enum value becomes a string when SSR #360

Closed Syunki0403 closed 4 months ago

Syunki0403 commented 4 months ago

I posted a similar issue on "protobuf-es" and received a response that there might be a problem with "connect-query-es", so I posted an issue on here as well.

The problem is that the enum type value becomes a string when it is an SSR and a number when it is a CSR.

Please check the issue ticket below for more information on the situation. https://github.com/bufbuild/protobuf-es/issues/784

thanks.

paul-sachs commented 4 months ago

Hi @Syunki0403, it might help to provide some additional context about how you're using SSR. I think I'm able to reproduce what you're talking about using NextJS. The problem is that NextJS serialization scheme defaults to toJSON which will serialize any enums to strings instead of numbers.

Currently there's no consistent way to customize how nextjs platform serializes but you can use select to transform the data. toPlainMessage is one i've seen used before, since it structures things very similarly, and provides a basic object version of your response (so spreading etc works more consistently).

As an example, you could do something like:

import { useSuspenseQuery } from "@connectrpc/connect-query";
import { customMethod } from "../gen/custom_service-CustomService_connectquery";
import { CustomResponse } from "../gen/custom_service_pb";
import type { FC } from "react";
import { PlainMessage, toPlainMessage } from "@bufbuild/protobuf";

const SubComponent: FC<{ thing: PlainMessage<CustomResponse> }> = ({
  thing,
}) => {
  return <>{JSON.stringify(thing)}</>;
};

export default function Home() {
  const data = useSuspenseQuery(
    customMethod,
    { name: "hello" },
    {
      select: toPlainMessage,
    }
  );
  return (
    <main className={styles.main}>
      <div className={styles.description}>
        <SubComponent thing={data.data} />
      </div>
    </main>
  );
}

It does have the side-effect of component that accept the response/input needing PlainMessage<...> generic, but since nextjs cannot serialize the functions on the Message class, it's an accurate representation.

There's more discussion of these options in issue #55 and there's more documentation here. I hope that helps.

paul-sachs commented 4 months ago

Closing this issue. We can reopen it if the previous comment doesn't suffice.