Should I use a nestjs pipe, guard or I should go for an interceptor? - nestjs

Well I have a few pipes in the application I'm working on and I'm starting to think they actually should be guards or even interceptors.
One of them is called PincodeStatusValidationPipe and its job as simple as snow. It checks the cache for a certain value if that value is the one expected then it returns what it gets otherwise it throws the FORBIDEN exception.
Another pipe is called UserExistenceValidationPipe it operates on the login method and checks if a user exists in DB and some other things related to that user (e.g. wheter a password expected in the login method is present and if it does then whether it matches that of the retrieved user) otherwise it throws appropriate exceptions.
I know it's more of a design question but I find it quite important and I would appreciate any hints. Thanks in advance.
EDIT:
Well I think UserExistenceValidationPipe is definitely not the best name choice, something like UserValidationPipe fits way better.

If you are throwing a FORBIDEN already, I would suggest migrating the PincodeStatusValidationPipe to be PincodeStatusValidationGuard, as returning false from a guard will throw a FORBIDEN for you. You'll also have full access to the Request object which is pretty nice to have.
For the UserExistenceValidationPipe, a pipe is not the worst thing to have. I consider existence validation to be a part of business logic, and as such should be handled in the service, but that's me. I use pipes for data validation and transformation, meaning I check the shape of the data there and pass it on to the service if the shape looks correct.
As for interceptors, I like to use those for logging, caching, and response mapping, though I've heard of others using interceptors for overall validators instead of using multiple pipes.
As the question is mostly an opinionated one, I'll leave the final decision up to you. In short, guards are great for short circuiting requests with a failure, interceptors are good for logging, caching, and response mapping, and pipes are for data validation and transformation.

Related

Is it a good idea to make one graphql response type for all queries and mutations?

What if we make one type that includes all state user can get from the backend. Lets call it AppState.
And there will be only one query getAppState, and all mutations will return AppState as well so that clients can access any field they need, and if you use apolloClient, clients' cache will update automatically.
We can get all state on user login without any problem.
Is it a bad idea?
Following this pattern would exactly contradict the reasoning behind the existence of GraphQL itself.
The idea is for your queries and mutations to exactly fit a pre-defined expected outcome. If you actually implemented such a concept, unless you provide all the data a query or mutation expects, it will throw an error. Subsequently, if you would actually end up trying it, you will quickly realize how cluttered and resource-heavy it actually is. Imagine fetching all your databases with each request because of this schema .... that would be awful.

Which layer should I use to factorize the existence checking of a ressource?

I'm trying to factorize the fact that for all routes that are similar to : /ressources/:id/* we should always check the ressource existence.
I'm not sure how to do it the proper NestJS.
Should I use a middleware, a guard or even pipes (it can be seen as a kind of validation) ?
Hope my question is clear enough,
Thanks in advance
I would say that a pipe is a proper spot in this case, as a guard will return a 403 and a middleware runs the query to your database before you've authenticated the request. You can also use DI in the pipe to make the queries to the database easier, and use the pipe only on the body or request param, depending on how you want to handle things.

How to overwrite generic ODATA expand handling functionality

We are currently working on performance issues with our provided OData interface, since the UI5 issues a read request with multiple expand paths attached. Due to the generic handling of the request by the framework this leads to an additional processing per expand option, which we need to prevent.
Reading the blog about this topic there seems to be a way to overwrite the generic handling somehow:
https://blogs.sap.com/2018/03/19/sap-cloud-platform-sdk-for-service-development-create-odata-service-7-more-navigation-read-create-expand-sqo/
In this case it is us who need to decide if we can afford to rely on the FWK-functionality. Of course, such generic support cannot be performant. But for small amount of data it is just nice to get it for free.
Stay tuned to learn how to overwrite such generic FWK-functionality with own specific implementation.
However, there is no further blog post on this and looking through the framework, my only idea to overwrite this would be to configure and use an own com.sap.gateway.core.api.provider.data.IDataProvider implementation which handles the request in a custom way, although this would be an immense workaround.
So the questions is if there is some leaner or easier approach to overwriting this functionality which I missed?
UPDATE:
I was update to create a custom data provider and register it with the RuntimeDelegate after servlet initialization. This custom data provider would then check for a custom annotation on the mapped method handler to see if expand should be handled or not. If not it will just read the entity, but not perform he generic expanded read. This works more or less fine, but what is of course missing is a way to pass the properties to be expanded in the ReadRequest. So far only a static implementation is possible solving our performance problem, but I would gladly have a hint if there is another, better solution for this...
At the time of this writing, no better approach exists at the moment.

how to implement postprocess filtering of response as middleware in node?

As part of authorization-rules I'd like to centralize logic as to what fields of a json-response are returned to the user.
To me, it makes sense to somehow implement this as some sort of postprocess-filter implemented in node-middleware.
Apart from the question whether it's considered good practice to change the output of a REST-endpoint based on some authorization-rules (I'm not sure, please share if you've got a strong opinion), I'm uncertain how to implement such a post-process filter.
I tried to implement it by listening to response.finish and have the filter kick in, but that's too late. i.e.: the response was already send.
Instead, what would be considered best practice for post-processing responses in Node?
you can perform your data operations at any part of communication chain, so if require to do some post data filter you can do your CRUD operations in a middle ware and then filter it in other step something like
AUTHENTICATION-(next)->AUTHORIZATION-(next)->OPERATIONS-(next)->LIMITS-(next)->RESPONSE
where each step except RESPONSE reffers to a middleware that will alter the request object with the pertinent information to pass to the next middleware

Returning a Status from the Domain

In our domain-driven application, we use a type called ServiceResponse<> to send data between layers of our application - specifically, one is returned by every method in the domain. As of right now, it encapsulates the data (if any) which was returned from the method, or any errors that it may have generated.
My question, then, is this: is it an acceptable practice to add fields to this object that may be useful in other layers of the application? For example, is it good form to add a Status or StatusCode field to it that may be interpreted later by the service layer for use as an HTTP status code (with or without some mapping)?
It sounds like a fine place to me. The idea that every method returns a "response" of some sort smells a bit like trying to decouple too much, but there are some cases where such extreme decoupling is warranted.
In any case, the ServiceResponse could easily have a status, and if it needed one, that is where I would put it.

Resources