We are making the move to ts and I have some question for which I could not find any simple answers so far. So I hope to get updated opinion in this post.
1/ Is it useful to have both TS and simpl-schema ? it feels like they are partly redundant but simpl-schema has the validate method to ensure checking before inserting/updating data. However it seems very redundant to have both, especially when you have to declare both the types and the schema for all your collections. How do you handle this ?
2/ Do you have any up to date example app of meteor/typescript/react. While the basic boilerplate exists I could not find a little more advanced project that is using this stack. I don’t think any of the tutorials use typescript unfortunately.
3/ Any other ressources you would advice to jump (hands on meteor/react/typescript ressources) ?
There are definitely benefits to having these two in sync. I typically use a mix of technology to make this happen. Most recently I’ve been using GraphQL and Apollo to get those benefit, and sort of leaving Simpl-Schema/Collection2 behind for a bunch of reasons.
In another pure Meteor app, I used some really cool JSON Schema → typescript tools, with some runtime validation in methods running through ajv (validators generated from JSON Schema). I never set it up, but you can use the same JSON Schema in the Mongo tier, for additional type safety. Since the ajv validators were run in mdg:validated-method I had full stack runtime data validation which was in sync with my static type validation through typescript. All my validators and types were generated at once with a script. Wonderful.
I’d recommend one of these two approaches, instead of using Simpl-Schema/Collection2.
We don’t intend to use graphQL on this project but I have been using it on other and indeed it helps a lot.
For your second proposal I’ll have a look, didn’t know about these validators but if I understand well they full replace a simpl-schema.validate function ?
Would you have some code examples of this implementation you mentioned, seems neat!
@captainn So in your first example, do you sync SimpleSchema with graphQL and Apollo, or do you completely stop using simpleschema? It’s not very clear, given how you phrased it.
I completely stopped using simpl-schema and collection2. At first, I moved away just from collection2 (it has some edge case failures that were blocking work). I did that by moving from validating with collection2, to manually validating in my methods. All inputs ran through methods in my app, since I don’t use client side updates (and no one should), so it wasn’t a massive lift to change over.
But eventually, I wanted typescript, and once I figured out how easy it was to validate inputs manually, I started looking for alternatives to Simple Schema. I wanted to keep using the awesome convenience maker that is uniforms, so I explored the schema formats that they support, which is GraphQL, Simpl-Schema and JSON Schema. Once I figured out how JSON Schema worked, I rewrote my schemas in that, then set about generating types and validators from that. And it works AMAZINGLY well. (Correction: I originally wrote that I used Simple Schema, instead of JSON Schema. Late night posting…)
I’ve even gone in the other direction - take a typescript/flow document provided by an API vendor, generate JSON Schema from that, then generate a validator, to make sure I validate my API inputs (always validate your inputs! even from APIs).
None of that was possible with Simpl-Schema and collection2 - or at least, it wasn’t as easy (I still don’t know how to make types out of it, seems cumbersome). And this is not to disparage Simpl-Schema. I’ve used it for years, and it’s served my needs very well. I appreciate all the work that went in to it all. For me, it was just time to move on.
I think I have an entirely different approach, so let me share it as well.
No, it’s not redundant at all. As @rjdavid said, TypeScripts is for the programmer to prevent runtime errors (here: invalid data) from happening. Then the SimpleSchema is actually checking the data.
However, you don’t have to use SimpleSchema to do that. Even the Meteor-native check function may be enough in some cases, at least as the amount of validation you perform is relatively small. (It also lacks a proper error reporting and that may be needed, especially for the end-users.) If you’ll use @types/meteor, check becomes a handy type guard (source):
I do use it quite extensively, especially when the input is sort of “internal”, i.e., I don’t care about the error message.
I do agree, it’s awesome to have them in sync. But it’s also tedious. Some time ago I’ve experimented with automatic type inference for SimpleSchema (TypeScript 4.3 and SimpleSchema), but I didn’t use it in the end. And that’s not because it won’t work, but because I’m trying not to use SimpleSchema at all.
When it comes to GraphQL, I most often go with the schema-first approach, use GraphQL Codegen to create TypeScript types, and then implement the already typed resolvers. (Just keep in mind, that the validation in GraphQL is very limited: no “minimum length”, “maximum value”, etc. You have to do it with custom in-DSL directives or directly in the resolvers.)
That’s a great one, really! There are so many great tools to work with JSON schema (including uniforms), that it’s not only easier to work with but also definitely more future-proof. If it matters for you, you can also share the schema with 3rd parties, like external integrators.
What is more, you can use the same JSON schema both in-app (for validation) and directly in-MongoDB (for ensuring data consistency). Of course, the latter is something that should never be needed, but it’s good to have it. Check out Using built-in MongoDB schemas for more.
That’s one of the advantages of cross-technology standards. I can also recommend doing the opposite, i.e., write code that generates both the types as well as the schema (and then use the schema to create a validator, using ajv). One tool I strongly recommend is typebox.
I also have used it for years. And probably will for a couple more, in some projects. But personally, I do switch to JSON schema whenever possible. Same goes for aldeed:collection2 and universe:collection - I try not to have any sort of ORM/ODM at all and handle the raw (helper-less) objects instead.
First of all, my personal relation with simpl-schema has never been good. Never got what’s under the hood, never fully understood the documentation. Another disadvantage, that others might experience as well, is that if you want to provide error messaging in any other language than english, you can’t use it. So now I’m using mdg:validated-method and Meteor.methods (if needed, for instance when using Stripe), together with check / Match, and I code in Typescript. Works well.
SimpleSchema is very useful for complex form validation and with collection 2 for complex insert and update validation that goes way beyond type safety
True, my bad. Thank you for pointing it out. Still made my own, because in Dutch and English, in the time that the i18n package I used became unsupported. So combining with that.
A few months back, I made this small library to generate typescript interfaces based on schemas: schema-to-types
I find it useful for type-checking the input received in meteor methods, while having runtime check with schemas.
I do define my own interfaces manually for the rest of the application, but it’s a nice addition for methods, exclusively.
Please don’t hesitate to comment or contribute to the library!
Curious, how did you handle validating a subset of the ajv schema? I’m hoping to define the schema once for a collection and then when I call a method, validate only the arguments that are passed in. I think I’ve found a way to validate each argument one at a time but it’d be nice to just pass an object of the arguments and validate once.