Improve DTO types, validation and serialization #1003
Labels
Blocked: Needs more info
This is lacking essential information like steps to recreate or a video showing reported behavior.
Type: Dev/Internal
Something that is more internal to development than end user facing.
We've been discussing this for over a year and wanted to start getting some concrete plans written out. Haven't finalized anything yet, using this issue to collect my thoughts.
Definitions
To set the scene, overall we're concerned with data. Not gonna get bogged down in domain objects/models/entities/POJOs/whatever terminology, I'm just calling things objects, then let's distinguish:
Both serialization and validation is a considerable amount of work, running on the main thread. A significant reason why Fastify is faster than Express is that it uses fast-json-stringify
Goals
Provide simpler types for our DTOs
This is really the main reason I want to do all this. The frontend makes use of these constantly, and I want to be able to use them in Panorama as well.
Currently our real source of truth for our types is the Prisma schema, but the types it generates are horrific. I'm not even going to try paste what they look like here, they're completely unreadable and composed of multiple types dotted around the 60k line TypeScript file that Prisma generates. There is no way we use these with Pano. They're far too unwieldy, and require installing the Prisma dependency and running the generate script to even use. Not making game devs have to do all that just to use what should be some relatively simple types.
Also,
We could use a generator for generating simpler types, I actually messed around with this about a year ago. But again we want types for our DTOs, which will differ from Prisma types anyway, and I don't want to add some insane system using comments in the schema for expressing the differences.
The current solution is to hand-maintain
.model.ts
files for every DTO, but make them derive from the Prisma type. Here's an example (user.model.ts
):avatar
we don't want, since the DTO transforms it to an actual URL pointing to Steam's CDN; we just store the actual ID.roles
andbans
are really just numbers, but they're using a branded type to makeBitfield
s mutually incompatible, and to highlight they're a bitfield.profile
isn't a Prisma type, it's one of the same DTO/.model.ts
types andUser
. We need to do this for all relational types.Given that we're doing these
.model.ts
files already, the simplest solution is to just manually enter in every field by hand. I have no issue with doing that, we're never going to have thousands of tables, it's not a big deal. However I think it's very much worth ensuring that our DTO types (.model.ts
types) are still assignable to Prisma types; when we modify our schema we want any changes to cause type errors.However we need to do this in such a way that Panorama can use the types without having any Prisma dependency. I want the process of pulling types from this repo to the Panorama repo to be as simple as possible, and therefore I actually think we should just use a node script that yoinks the source files and scrubs any Prisma stuff, nothing else.
constants
all the time and don't want the hassle of web devs having to PR into two different repos whenever they change something.constants
as an NPM package would be hard to do and bad for developers, you'd have to update the package before you could access the changed types.So I think a bash script that clones this repo, and copies just stuff from
libs/constants/src
into a subdir of the Pano repo would be easiest, just Git CLI and some coreutil stuff to remove lines matching the Prisma checks. Happy to hear other alternatives but IMO this is the best approach. Would look something likeNot have multiple sources of truth for our types
types separate from Prisma is worth it IMO but annoying to have that plus DTOs. but not all that bad idk. This makes Typia/Nestia very appealing, we'd just have the prisma schema then the DTO/
.model.ts
files.Swagger docs generation
ct/cv are fucking slow and ugly
this probably isn't a huge deal, we're using prisma of all things, which is a huge perf hit according to our traces.
Current Setup
I don't like CT/CV but
@Expose
and@Transform
are very helpful!Ideas
I realised today we could use Postgres generated columns + SELECT (Prisma has
omit
now which is nice) in place of@Expose
and@Exclude
. Requires manually modifying migration files but I'm not against this.See https://github.com/nikolasburk/generated-columns
Various approaches we could use on top of proposed type changes:
ClassSerializationInceptor
to let fastify do it's serialization, without schemas for outgoingThe text was updated successfully, but these errors were encountered: