Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Show HN: Remult – a CRUD framework for full-stack TypeScript (github.com/remult)
130 points by yonirapoport on May 22, 2022 | hide | past | favorite | 52 comments


Hmmm, exceptions in validation! Debugger hell.

  export class Product {
    @Fields.string<Product>({
        validate: product => {
            if (product.name.trim().length == 0)
                throw 'required';
        }
    })
    name = '';


This can work if the controller uses a try catch and handles the exception properly passing the error up the chain to an error output from the rest controller.

Personally I hold the errors in an array which is useful when validating a form when you want to show multiple errors from a save attempt.

However I do throw an exception if the model is somehow incorrectly configured. Like a validator method being expected but not defined.


I see this a lot with Java style validations. Everything is an exception or can be one. Try catch hell everywhere and there are two schools of thought. Let the exceptions bubble up. Or catch the exceptions you expect at the abstraction, letting the rest bubble up.


Exceptions are imperative, but validation should be declarative (only requires pure functions to work out validation state given stateful input parameters).

Exceptions are a really bad match for marking validation (even ignoring the arsefest that is debugging exceptions during keyboard input events - ugggh).

The DOM has onInvalid events[1] that are fired on form submit (not blur), and there is an :invalid[2] pseudo class for highlighting input errors. Not a perfect API, but certainly relevantly interesting.

[1] https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputEl...

[2] https://developer.mozilla.org/en-US/docs/Web/CSS/:invalid


Well that's weird since java validation frameworks usually collect validation failures before throwing.


I'd prefer if they wrapped https://mikro-orm.io/ instead of inventing their own.


Similar, one of my fav TypeScript CRUD tools is TSOA. It generates OpenAPI specs from regular type information on functions. https://tsoa-community.github.io/docs/introduction.html


Unfortunately like almost all Node libraries, it isn't very mature or well-maintained. I stopped using it because it was too rigid and missing vital features.


Could you expand on which features you found were missing?

I use tsoa and am happy with it but often choose NestJS these days as it’s much more structured.


How does this differ from Prisma? https://www.prisma.io/.

I do like the quick bootstrapping Remult offers via "JSON db" if one hasn't set up a DB yet. And entity classes defined as a .ts file is nice, as opposed to Prisma's DSL (e.g. schema.prisma file).


Seems pretty different. Prisma is an ORM basically, while this generates HTTP REST endpoints for you.


Prisma focuses on backend<->db while Remult also handles frontend<->backend


I see. Prisma does generate a FE client though (PrismaClient) that essentially can be dropped into NextJS API routes (or, more directly, used in the getServerSideProps method on a next js page). Thus its fairly integrated across the stack. (Not trying to jack this thread to peddle Prisma, just a longtime user of it and trying to find similarities).

It does seem feasible one could use Remult + Prisma + NextJS, with Prisma as Source of Truth of DB schema and Remult Source of Truth for Client side data model (although, that might go against the "define once, use anywhere" pattern laid out here).

Really like the project though, great docs and tutorial.


Decorators are tiring.


I’m distrustful of them. I’m not sure what version will be approved and what version has been ruled out, invalidating some swath of libraries.

Can anyone provide a succinct summary?


There is an implementation proposal [0] is at stage 3[1], which means it's likely to land. Unfortunately, there is no set timeline.

- [0] https://github.com/tc39/proposal-decorators - [1] https://tc39.es/process-document/


I was stumped on how to integrate Postgres schemas + TypeScript types, so I visited HN, and this thread helped me move forward.

My project is a game, the client/server uses WebSocket rather than a normal REST API.

I have used Prisma, Knex, TypeORM. Seems to me that ideally, we would write types in TypeScript and have a DB schema generated from those, including automatic migrations based on schema diffing like Prisma. Then we only need to know TS, not another DSL.

We don't want to generate TS types from the DB because then we have no way of versioning the DB schema (except by writing SQL or DSL migrations).

I ended up finding https://deepkit.io/library/orm and I'm going to try it out. (Not associated with project)


are you familiar with mikro-orm ?


Thank you for mentioning it, that made me take a re-look. I find the schema generator doc[0] hard to digest. But I do like that it uses the 'do one thing well' philosophy. Deepkit allows using just the ORM package, but I appreciate how detailed the warnings are on the mikroorm doc.

0: https://mikro-orm.io/docs/schema-generator


Very well thought out. Demo at

https://remult-crm-demo.herokuapp.com/

Username: Velva

Password: password

Front end of the demo is functional but a little rough on my iPhone with Safari.


It seems to already be filled with racial slurs unfortunately.

Also, pressing enter to log in doesn't work.


Another alternative is tRPC.


Bundle some Dockerfile/docker-compose.yml/k8s yaml/k8s Helm charts/Terraform examples maybe?

https://docs.digitalocean.com/products/app-platform/how-to/a...

https://devcenter.heroku.com/articles/heroku-button


Good idea. Thanks!


I may try this out since I am handrolling something similar for a project but I am strapped for time. Only thing is I am generating types from an openapi spec and sharing the types with ui as a dependency. I somewhat prefer that approach as I end up with an openapi spec and I don't need any framework whatsoever beyond perhaps a dev dependency on type generation from openapi doc


I like to use Hasura to give me full GraphQL access to a PostgreSQL/MSSQL database and then I can use graphql-codegen to get real, schema-based frontend types with no need for more tools than Hasura and graphql-codegen. Not sure that'll help you here but it's a thought.

I will note the MSSQL version of Hasura seems to be slightly behind in documentation, not sure about features though


unfortunately I am in the anti-graphql camp


Why? It has meaningful schemas and therefore type generation, and it performs really well on an implementation like Hasura

Surely swagger isn’t a better tool than Hasura and GraphQL-codegen


What are you using to codegen the types?


I haven't done it yet. I've just set up a monorepo and prototyped sharing of types from backend to frontend. Googling it seemed like there were some decent options for type generation from swagger, i.e. https://github.com/drwpow/openapi-typescript


Take a look at https://github.com/bcherny/json-schema-to-typescript, too. I used it successfully at a previous job. IIRC, I had to write some code to convert OpenAPI to JSON Schema but it wasn’t onerous


This looks really nice. Are there any other competing frameworks in the TS space? Would be curious to hear about folks' experiences.


I use Nest as my TS backend framework of choice.

It just works great, covers just every use case I throw at it (business apps or side projects), has the right balance of versatility and openness, and doesn't try to do more than backend.

I really love it.


I hated Nest, you have to learn their "magic", it was continuously in my way instead of helping me


This is totally off topic, but I am glad to see this here. Nest.js seems really powerful on the surface, when you start reading their docs [0] everything makes sense at first. But the deeper you go, the more it sets in that the complexity introduced by its "magic" results in very little being easily reasoned about. Just look at the process for building a GraphQL API [1], for example, it starts out simply enough then goes off the deep end. Decorators, dependency injection and providers within providers all the way down.

[0]: https://docs.nestjs.com [1]: https://docs.nestjs.com/graphql/quick-start


I went down that rabbithole when I had to set up Graphql with federation. The reason it seems complicated is because they're attempting to fit bootstrap processes of different libraries into their own IoC style by writing tiny wrappers.

You end up with large blocks of config in ugly decorators but what they're doing is trying to supply that config to the underlying libs.

I consider Nestjs docs to be among the best written docs in the node community. Virtually everything you need is in there.


agree. "inversion of control" doesn't work well for the backend. Had an issue with the frontend due to what I thought was CORS. Putting a simple 'console.log' in nestjs doesn't work... had to write an 'inversion of control' custom logger to find out it wasn't a CORS error but double slashes '//auth/me' vs /auth/me because of environmental variable. A simple console.log could have fixed this but instead it took several hours of research. Really? Why? makess me think nestjs is built for billable hours and frustration... Asking for help you get treated like a jr developer.


You’re not kidding at all. I discovered a problem with their implementation of Bull queues, and the attitude of that crowd was something else.

Despite that, I quite like NestJS, but I am a bit concerned about their — and Remult’s — reliance on decorators, a standard that appears to be in flux.


I don’t get it. Of course you can use console.log?


So I spent a lot of time in the Nest ecosystem, and I wrote some nontrivial libraries with a little (not a lot) of uptake (and neither are actively maintained at this point, so these are here mostly for completeness):

https://github.com/eropple/nestjs-auth

https://github.com/eropple/nestjs-openapi3

I was pretty excited by NestJS when I ran into it because, well--I don't mind magic, when it's done right. I quite like Spring Boot, for example. But NestJS's magic is...incorrect, in a lot of ways. The DI container is a little bit scary, with oddly hardcoded ways to register interceptors into request scope (itself necessary because NestJS's logging facilities aren't--or weren't at the time--decorating requests with X-Request-Id or similar, so you had to register your own) and no way to then define interceptor order.

It also has a lot of really overlapping nouns; guards are interceptors but less capable (and @eropple/nestjs-auth didn't use them at all) and the "pipe" concept for validation was itself inscrutable. To make it usable, I ended up just doing everything with decorators and interceptors, all living in request scope. And once I'd gotten it going, it was pretty nice. But it also meant broad incompatibilities with much of the NestJS ecosystem. It was mostly just my magic, instead.

These days I use Fastify, and, well--some things never change:

https://github.com/eropple/fastify-openapi3


I haven't been following the Node ecosystem closely. However Fastify is really interesting. Why choose Fastify over Koa? I've never understood why Koa gets so little love from the Node.js community.


Fastify has, IMO, a better Typescript story than any other framework, particularly with Fastify 4. I also prefer Fastify's ergonomics around plugins as scoping to Koa's Connect-derived approach, and I don't really love having a `ctx` object as opposed to req/res (but that one is purely a taste thing).

For me, if I wanted what Koa does, Express does 90% of it and I already know it off the top of my head. And I don't really want Express because I'll have to reinvent a lot of wheels or stack a lot of sorta-compatible middleware on top of one another (Fastify's ecosystem is smaller but generally pretty cohesive).

Nothing at all wrong with Koa, to be clear--I just don't have a use for it.


Super cool. I'm gonna give Fastify a shot next time I'm in Node.js land. Thanks!


I thought nest was somewhat straight forward, minus the use of the angular module system, but I spent years using Java/Spring. That said, nest didn't have a component scan so you have to manually specify services per module.

Having spent more time using typescript and picked up functional programming similar to Haskell (via fp-ts), I wouldn't touch nest despite its popularity.

MarbleJS looks interesting. But I'd also be inclined to use express with supporting libraries.


Interviewed recently with a startup that said they're moving from Hapi over to Nest. Lol... maybe it's for the best things didn't work out.


I totaly agree. Have used it for years and still does.


I feel like this would effectively be an alternative to Blitz.js or tRPC


ChiselStrike


I love the idea of this. I’ve written something in the same vein but it’s a websocket transport and it has a shared vuex store. So basically mutations are sent across the wire and it has logic for dealing with conflicts.


what is the advantage over next.js-typescript?


It should be an addition to next.js not a replacement. It adds the CRUD capabilities, strong typing, entity code sharing…


Very impressive, a star well deserved




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: