API with NestJS #3. Authenticating users with bcrypt, Passport, JWT, and cookies
wanago.io
wanago.io
Its basically Spring/.Net MVC implemented in TypeScript. That makes it a great choice for .Net/Java developers who are transitioning to coding for Node.js, but for anyone without that background, it comes with a steep learning curve (Dependency Injection, Inversion Of Control, Aspect Oriented Programming... all the usual suspects of "enterprise" application development).
I'd say its positioned to become very popular (and you can see its trending strongly upwards on npmtrends.com) because so many enterprises are transitioning towards Node.js. Its like a cozy blanket for ex .Net/Java developers.
I always find it amusing that that Nest.js is a back-end framework, that was inspired by a front-end framework, which was inspired by a back-end framework. (Nest.js -> Angular -> Spring MVC). :-)
If anyone's wondering my current template is routing-controllers, class-validator, tssyringe, and sequelize-typescript.
Separate issue, but if anyone can suggest a different query builder / orm in typescript that'd be truly appreciated. Imo typeorm is too much of an abstraction and sequelize works but requires custom types ever since v5
Class-validatdor puts you in a deep hole, though. Consider ajv; it's what Fastify uses under the hood. (Honestly, just consider Fastify. It's great.)
You can still achieve the loose coupling of DI by using custom providers [0]. Basically, this approach is the full syntax for defining providers and gives you the most flexibility (inject based on Class or token, provide factories, simple values, class instances, etc).
[0]: https://docs.nestjs.com/fundamentals/custom-providers#custom...
Anyway, IMHO, Typescript isn't designed for dependency injection in mind. Microsoft also has a DI library [1] but it feels like too much wiring to compensate for the lack of compiled interfaces.
I've used Nest.js extensively over the past year or so and I find the documentation extremely lacking. Sure there might be a lot of hello-world style examples, but advanced or sometimes even basic usage is often not well documented and the actual API itself is completely undocumented (you might have an example of 1 way to call a function, but that's it).
You often have to piece together examples from various "Documentation" pages, which should really be called Examples, or dive deep into source code to find the list of functions or parameters that are available.
Another pain point is that I sometimes ran into extremely hard to diagnose issues with Nest. I had to add Swagger documentation to a project recently, which uses previous version of Nest.js (v6). It turns out that the latest version of @nestjs/swagger is not compatible with this version of Nest.js, but the docs don't mention which version you should install to get it working.
I installed the library as described in docs for Nest.js v6 and used their example to include it in the project. When I started the application, it didn't print any errors or really produce any useful output at all (besides all the DI logs and the fact that initialization was successful). Instead, the application simply fails to print "Application Started" and it just doesn't listen on a port.
I fixed that by comparing release dates of older @nestjs/swagger versions with release date of NestJS version that we were using. There's nothing to go on in cases like this and whenever something like this happens (multiple times over the past year for us), you can probably imagine how frustrating that is.
With TypeORM, we also frequently run into issues that haven't been addressed in years[1], missing functionality in their query builder[2] and strange behavior in general.
I commented about this previously[3], also I should point out that I appreciate the effort they are making, but I would recommend that anyone considering using Nest.js in production takes a hard look and really evaluates whether it supports all of their use cases. In our case, it looked really good on the surface, but once we got deeper into the project it started showing a lot of its warts. Expect to do a lot of babysitting with this framework if you venture outside of their narrowly documented use-cases.
[1] https://github.com/typeorm/typeorm/issues/2065
I wasted too many cycles trying to understand how it was secure while debating how much latency my database check was introducing on every single request compared to those simply using the JWT as-is.
It has made something I considered "settled" to be a time-sink.
(Nb. I've not personally seen them used in a case for which they make sense, yet, but only in smaller projects because they're trendy)
Another thing one must be aware of with JWTs is protecting your users against XSS and CSRF's. Make sure your shortlived token is stored on localStorage and the refresh one is stored in a cookie.
Unless you mean blacklisting tokens, then, yes, you do need to check your blacklist, though fanning that out to an edge cache should suffice and keep you from needing to hit your authentication service or database every request. But that's true for any long-lived session token.
With stateful authentication, solving this is trivial: just check your tokens/sessions/whatever against a centralized database every request.
But when I see how TypeScript looks like JS+C# it feels like OOP people just can't help themselves
Toy systems that just do MD5(MD5(password)) are screwed because they don't have any salt, but PHK MD5 uses salt so all the time-space tradeoff attacks are made irrelevant, bad guys will need to brute force each account they want to attack individually.
If which crypto hash to use is a major security consideration you are already Doing It Wrong™ because the only point of these systems is to store human memorable passwords, and human memorable passwords are hot garbage anyway. Either outsource the human authentication problem to somebody else or, if you are quite sure that's strategically unsound (e.g. you want to be Amazon or Apple with fingers in every pie) then require passwords not match PwnedPasswords and either mandate or at least strongly encourage a second factor, with at least TOTP and WebAuthn options offered.
It’s one thing I really hate about almost every tutorial or example that’s out there, they just pull in dependencies out of nowhere.
If you go the Nest + Angular route, I recommend checking out NX monorepos, which adds another level of seamlessness. NX was created by former Google/Angular team members. One of my favorite features includes the ability to easily share libraries/models across the front end and backend. E.g., if you're designing an API, you can import the same model file to both the front end and back end, ensuring no divergence between both sides as the API is redesigned.
To be fair this applies to any case where you have the same language on the front and back, which was one of the main motivations for Node in the first place
1. nx g @nrwl/workspace:lib data, 2. Modify the typed models/interfaces. 3. Import to backend + front end.
I use the same logic as where to put a font end component. If I'm creating a component for the first time, it sits in the same folder as the parent component. If I need to use it with another component, I refactor it into a common folder. If I create a string transformation function, it exists in the same file that is using it. If I need to use it somewhere else, it gets refactored into utils/strings.js which is a starting place for creating a library.
It solves the problem of 'where does this go?' and 'where did I put it?' 95% of code that I need to find will be physically next to the code that uses it in a file system. If not it will be neatly organized into a common use directory.
For the few times I need to refactor functionality, at that point, I will invest time to make a clear and adaptable API input and output contract.
Apparently .compare TLD hit General Availability in 6 May 2020.
Finally a great web application framework for NodeJS.
Nest + Typeorm + Postgres + Apollo + NextJS for front end = best of many worlds
People make a lot of hay about the NestJS dependency injection system, and my intuition is that a lot of it is that it's a novel concept to a lot of the folks running into it. If you come from a Spring or related background, however, I think it's pretty clear that NestJS has a pretty critical misunderstanding of dependency injection. Modules are hardwired together--`BarModule` requires `FooModule`rather than just declaring what they need and what they export and allowing the dependency resolver to figure it out regardless of what module they come from. As-is, you cannot replace a dependency coming from `FooModule` with one, say, from `Foo2Module` without changing every consumer. It's a high-boilerplate devolved service locator rather than dependency injection.
"Pretty critical misunderstanding" has become my default description of big parts of NestJS as I've gotten deeper into its use over the last year and a half. This description really does fit a lot of aspects of the system. It often feels as though the implementors read half a description of this or that, decided "that's a great idea!", and then implemented that half-a-description...poorly. The "microservices" concept (really just RPC, and not particularly play-nice-with-others RPC) is a good example, as is the really clunky access to WebSockets. CQRS is another prime example, as they've somehow implemented single-node CQRS, made it impossible to distribute, and declared victory and went home.
It is better to not provide official support for something if that official support is going to be so full-stop awful, because that official support will choke out attempts to innovate in the space because you've already taken the mindshare for the problem at hand. Which dovetails into the problem that will probably end up putting NestJS in the dustbin as soon as somebody else comes up with a competitor: the NestJS team seems to have what feels like at best an oblivious and at worst a rivalrous relationship with their community and with Node as a whole. Over the last year they've rolled out what read to me as lock-in, don't-play-nice-with-the-ecosystem-as-a-whole "features", like their poorly intentioned CLI "monorepo tooling rather than just using lerna for multi-modulestuff like the rest of the world. Also like the future-forecasted "Nest CLI plugins" for things like linting otherwise bonkers misbehaviors[0]. As somebody who's written a bunch of open-source modules for NestJS, I consistently get the feeling that Kamil would really prefer it if developers just shut up and took his stuff and made apps (maybe paying him along the way?), rather than building their own open-source stuff alongside it. I still have a very bad taste in my mouth from the way that they just stomped on the `nest-schedule` project by added a less-featureful but otherwise identical "cron-like" gizmo to NestJS core without so much as a nod to the community member who wrote the better one before they did. The idea seems to be that NestJS isn't a community, it's a single-source vendor, and in 2020 that's weird to me.
I've used a lot of NestJS but I can't really countenance using it for new projects, and I can't recommend it to others.
Nest.js tries to have "answers" for everything (i.e. CQRS, MQTT, Kafka, etc., etc., etc), but I do wonder how well implemented these answers are (vs. checking of a list of "completed" features.. Their documentation certainly looks impressive when it comes to breadth).
I think if you stick to the core concepts of MVC with some simple DI (and if you are building something that pushes the limits of that DI system, maybe its too big), Nest.js can take a team of developers new to Node.js and enable them to quickly build well structured applications (certainly with higher quality than the average express applications I've seen in the wild).
Do I think its the perfect swiss-army knife of Node.js server side development? No, but for a team of regular developers, I think it fills an important void in the Node.js landscape (the same void that was filled by Spring MVC in Java).
As with everything tech related, it all depends on the use case.
If there was a roadmap and a set of principles for governance I'd feel much better about it, but I also have trouble seeing that ever actually happen.
> I do wonder how well implemented these answers are
Not well, tbh. "Microservices", as mentioned, are useless. CQRS is fundamentally misunderstood. Their OpenAPI 3 libraries (and I will cop to some bias here, my frustration with their OAS implementation got to the point where I wrote a better one[0]) are implemented in a developer-unfriendly way that's totally separated from validation so there's a ton of diplication of work. (And let's not even talk about validation! `class-validator` is a mess. "Pipes" are pretty silly as a concept. Fastify uses `ajv` under the hood; there's not a great reason why everybody else doesn't, too.)
As you say: checkmarks. A lot of checkmarks. But then you pick up the corner of the carpet and the subfloor's chewed through.
I'm agnostic as to ORM layers but both Objection and TypeORM are worthy of consideration. My project's DI container will play nicely with both--it supports dynamic scopes and so it's really easy to do something like "create a transaction scope and request a service from it, and that service automatically wires up transition-backed TypeORM repositories." Which is hard, hard sledding in existing systems.
I hope to open source it relatively soon.