Build a validation parameter decorator in typescript - node.js

I read the doc, been there, done that. Still no clue how to write a decorator I need in a way that makes common sense.
In brief: Got an interceptor that executes before the validation layer. That simply means that invalid data can get in the interceptor and break the app. To avoid that I would like to use a decorator on some methods, and to be more accurate on parameters of such methods.
public async getUserById(#IsIntNumber() userId: number): Promise<UserEntity>
{
// method logic
}
Here #IsIntNumber() is a custom decorator that validates the userId parameter.
As a matter of fact I'd like to have a little library of mine in the application holding a bunch a that kinds of validation decorators that I could apply to different parameters.
Is there some legal method to do this without shedding too much blood and too many tears?
I know it's a difficult question.
In the docs they sort of say:
The #required decorator adds a metadata entry that marks the parameter
as required. The #validate decorator then wraps the existing greet
method in a function that validates the arguments before invoking the
original method.
Meaning I've got to pack all my validation logic into that validate function or what? Really?
Does it mean that we don't have adequate parameter decorators in TS? Cos if I understand this right, these ones are absolutely, totally unusable.

Related

What are the risks involved in using custom decorators as validation pipes in Nestjs?

Background
A data structure in my database consists of "sections"; lists of custom objects. The number of sections may expand in the future, so to keep my code as DRY as possible, I wanted to determine the section to add/update/delete an item from to be defined dynamically as a parameter.
I quickly realised that doing something like #Body() section: SectionA | SectionB | SectionC... disables validation so I needed a single DTO Section that could encompass all sections. To do that I need to define dynamically which validators to apply as I have several #IsNotEmpty constraints.
So I came across this post whose selected answer recommends the usage of groups.
This posed the following challenges:
I now have to write a custom validation pipe. Relied heavily on this
I want to override the global validator pipe that I already had running and use my custom one for just that method. Outcome: didn't work, had to start defining the pipe on every controller method, a tradeoff I am willing to accept. Looks like there is no simple alternative.
However, I'm now faced with the final problem: how to use the parameters in the request to define these groups in the validator; another brick wall. No simple solution.
Solution
This question has been asked here but no satisfactory solution was actually given.
Option one recommended redefining the scope of the pipe to "request" level but didn't explain how, and solutions found online didn't work.
The second solution, using a custom decorator to perform the validation instead, did work, very well in fact here is a simplified version of the code:
export const ProfileSectionData = createParamDecorator(
async (data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
let object = plainToInstance(SectionDto, request.body); // I don't need to access the metatype from the request because I know what type I need but I'm sure I could if need-be.
const groups = [request.params.profileSection];
let validatorOptions = { groups, ...defaultOptions };
const errors = await validate(object, validatorOptions);
if (errors.length > 0) {
throw new BadRequestException();
}
return request.body;
},
);
Implications?
Here's my question. When Jay McDoniel recommended using a custom decorator, they warn: "Do note, that this could impact how the ValidationPipe is functioning if that is bound globally, at the class, or method level."
What does this mean?
Are there any vulnerabilities or performance drawbacks associated with this solution?
Obviously, one drawback is that you are using validation outside a validation pipe which is not ideal from a point of view of order and single-responsibility but I can't think of tangible inconveniences beyond aesthetics and maintainability.
Knowing the background, would you have approached the problem in a completely different way?

Passing parameter to typescript decorators

So, I am working on developing a CRUD server in nestjs, using Mongo as the database, and I am trying to inject the database connection that can be obtained from the service constructor (#InjectConnection() private connection?: mongoose.Connection), into a decorator by doing #Decorator(this.connection). This is not possible because the decorator factory runs before the connection to the database has been initialised. With this being, every time that the decorator is used, the connection is undefined. Is there a workaround for this kind of situation? I really wan't to implement the solution using typescript decorators.
decorators in typescript has 3 arguments. target which is the prototype of the class, key which is the key that you are applying the decorator to and third descriptors which is to change the value of the key. essentially when you type #Decorator, typescripts sees it as a function. this is how you defined your decorator.
#Decorator=function Decorator(target:any,key:string,desc:PropertyDescriptor){}
now you want to write it like this
#Decorator()
that means you have add additional () to the right side as well. this is simple maths.
#Decorator()=function Decorator()(target:any,key:string,desc:PropertyDescriptor){}
what you have to do is you have define decorator as the function which returns a function with those parameters.
function Decorator(...args){
return function(target:any,key:string,desc:PropertyDescriptor){
// you can access to ...args here
}}

Does verifying the mock is need in minitest

I'm reading the mocking capability of minitest.
require "minitest/autorun"
mock = MiniTest::Mock.new
mock.expect(:use_any_string, true, [String])
mock.use_any_string("foo")
## mock.use_any_string(1)
## MockExpectationError: mocked method :use_any_string called with unexpected arguments [1]
## I do not understand the purpose for this
mock.verify
So I do not understand the purpose of using mock.verify since the trying to pass any another type(to use_any_string) other than String result in mock expectation error.
So why should one use assert mock.verify then?
You are right, you cannot set anything else to the configured mock, but if your mock is not called at all, then you can find out with mock.verify. So if your method under test should call the mocked method, you should verify that it was called at all.
You are correct, mock.expect(:use_any_string, true, [String]) will cause the test to fail if the expected call is not made on the mock.
However using mock.verify depends on how you compose your test. In your example you are explicitly calling the method you are testing with mock.use_any_string("foo") so there is no need to also call mock.verify.
You could get into a scenario where you are not making this call explicitly, or are expecting the mock to have had calls made at a certain time. These scenarios would take advantage of mock.verify calls.
(Another note, minitest has recently introduced assert_mock which can be used instead of mock.verify)

Using an OR statement with guards

What I am trying to do is something functionally like this (of course, the code below is nonsense):
#UseGuards( AuthGuard || AdminAuthGuard )
I want my guards to be false only if both return false. Basically, I'd like my auth guards to be like an OR statements because the endpoint can be activated by multiple independent sources and each has its own authentication system.
Of course, I could combine those two auths in the same function. The problem is that the code would become messy as there are instance where I need to use each of them individually and I do not want an overlap with one another.
Anyone has any idea how to implement a behavior like that?
PS: Also, as additional complexity, I am using RoleGuards with one of the two login system. So RoleGuards would be applied, for example, if AdminAuth is true, but not apply is normal Auth is true.
SOLUTION: Here's how I solved this problem(I still don't know if there's a simple nestjs way of doing it. If you you, I want to know ;)).
In my original guards, I exported the validateRequest function. I created an auth guard that is called adminOrNormalAuthGuard. In there I import the functions and implement the logic I want.
As for the roleGuards, all that I'm doing is importing those validate functions. If login is normal=> return true. If special login=> result depends on guards logic.
As this seems related to authentication, you can follow the recomended behaviour in the doc seen here: https://docs.nestjs.com/security/authentication#extending-guards
Basically what you can do is extend an AuthGuard composed with multiple strategies:
export class MyAuthGuard extends AuthGuard(['strategy_1', 'strategy_2', '...']) { ... }
Then you just have to set your new "MyAuthGuard" guard to your routes.
If the first strategy fail, the next one is used and so on until all strategy fails or one is successful.
As this seems related to authentication, you can follow the recomended behaviour in the doc seen here: https://docs.nestjs.com/security/authentication#extending-guards
Basically what you can do is extend an AuthGuard composed with multiple strategies:
export class MyAuthGuard extends AuthGuard(['strategy_1', 'strategy_2', '...']) { ... }
Then you just have to set your new "MyAuthGuard" guard to your routes.
If the first strategy fail, the next one is used and so on until all strategy fails or one is successful.
But in the docs, the description is:
In addition to extending the default error handling and authentication logic, we can allow authentication to go through a chain of strategies. The first strategy to succeed, redirect, or error will halt the chain. Authentication failures will proceed through each strategy in series, ultimately failing if all strategies fail.

How to mock an array of interfaces using powermock or mockito

I am mocking an interface array which throws java.lang.IllegalArgumentException: Cannot subclass final class class.
Following are the changes I did.
Added the following annotations at class level in this exact order:
#Runwith(PowerMockRunner.class)
#PrepareForTest({ Array1[].class, Array2[].class })
Inside the class I am doing like this:
Array1[] test1= PowerMockito.mock(Array1[].class);
Array2[] test2= PowerMockito.mock(Array2[].class);
and inside test method:
Mockito.when(staticclass.somemethod()).thenReturn(test1);
Mockito.when(staticclass.somediffmethod()).thenReturn(test2);
Basically I need to mock an array of interfaces.
Any help would be appreciated.
Opening up another perspective on your problem: I think you are getting unit tests wrong.
You only use mocking frameworks in order to control the behavior of individual objects that you provide to your code under test. But there is no sense in mocking an array of something.
When your "class under test" needs to deal with some array, list, map, whatever, then you provide an array, a list, or a map to it - you just make sure that the elements within that array/collection ... are as you need them. Maybe the array is empty for one test, maybe it contains a null for another test, and maybe it contains a mocked object for a third test.
Meaning - you don't do:
SomeInterface[] test1 = PowerMock.mock() ...
Instead you do:
SomeInterface[] test1 = new SomeInterface[] { PowerMock.mock(SomeInterface.class) };
And allow for some notes:
At least in your code, it looks like you called your interface "Array1" and "Array2". That is highly misleading. Give interfaces names that say what their behavior is about. The fact that you later create arrays containing objects of that interface ... doesn't matter at all!
Unless you have good reasons - consider not using PowerMock. PowerMock relies on byte-code manipulation; and can simply cause a lot of problems. In most situations, people wrote untestable code; and then they turn to PowerMock to somehow test that. But the correct answer is to rework that broken design, and to use a mocking framework that comes without "power" in its name. You can watch those videos giving you lengthy explanations how to write testable code!

Resources