Swagger + Nest.js doesn't remove empty DTO and model - swagger

I was creating documentation for Nest.js API using Swagger. The problem is what I removed documentation from this DTO or model, in swagger UI docs I can see it as empty object.
For example:
import { IsNotEmpty } from 'class-validator';
export class PostDto {
#IsNotEmpty()
readonly title: string;
#IsNotEmpty()
readonly content: string;
#IsNotEmpty()
readonly description: string;
}
Also I was trying to change name of this entity, using incognito mode, reinstall node_modules, but it didn't work. If I change name of this entity, it also changes there. What's wrong?
What I want to do, is by removing this documentation decorators, not to see those empty objects.

There is a CLI plugin provided with the #nestjs/swagger which will automatically add the annotations using reflection.
This means you NO LONGER need to individually annotate each property using #ApiProperty() etc.
The plugin is opt-in and not active by default.
In your nest-cli.json add:
{
"collection": "#nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": ["#nestjs/swagger"]
}
}
You can also change the default options:
"plugins": [
{
"name": "#nestjs/swagger",
"options": {
"classValidatorShim": false,
"introspectComments": true
}
}
]
See https://docs.nestjs.com/openapi/cli-plugin
Troubleshooting: if you are running in dev mode, may need to stop/start.

Related

NestJS inject service in guard

I am pretty new to developing REST APIs using the NestJS framework (started using it last week).
For Authorization purposes I want to implement a CanActivate Guard to my app. This guard simply looks for an authorization header to extract the jwt. Furthermore the user needs to be fetched via a service to get its role and check for the required permission. Additionally there is a #Permission decorator, which is used on protected routes, that takes in a permission string.
This decorator file looks like this:
export const PERMISSION_KEY = "requiredPermission"
export const Permission = (permission: string) => {
return SetMetadata(PERMISSION_KEY, permission);
}
But I am experiencing strange behaviour: Only injecting the Reflector (so I can look up the required permission from the route) is working fine. When now trying to inject a service, let's say AuthService, the constructor of the AuthenticationGuard isn't even called, so the service results in undefined. Event the reflector instance is undefined, though it worked before. Here is how it looks in my authentication.guard.ts:
#Injectable()
export class AuthenticationGuard implements CanActivate {
constructor(
private reflector: Reflector,
private authService: AuthService
) {}
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
// ... do some things to extract jwt from header ...
console.log(this.authService); // Results in undefined
// This line does not work because reflector also is undefined.
const requiredPermission = this.reflector.get<string>(PERMISSION_KEY, context.getHandler());
console.log(requiredPermission);
}
}
This guard is imported as a provider in a feature module called AuthModule:
#Module({
imports: [
JwtModule.register({
secret: "EXTREMELY_SECRET"
})
],
providers: [
AuthService,
{
provide: APP_GUARD,
useClass: AuthenticationGuard
}
],
controllers: [ AuthController ],
exports: [
AuthService
]
})
export class AuthModule {}
Now when removing the service from dependency injection and make a console.log, I can see that it gets instantiated as the first dependency of the whole app. Does this maybe cause the service to fail injecting? How would I possibly change fix that?
Or does injecting services not work for guards in general? I think this is not the problem.
Maybe someone can help me with this problem and give me some advice on to fix this issue.
Thank you very kindly in advance for your support!

Prescribed way to obtain env in hostBuilder.ConfigureAppConfiguration

Trigger-happy duplicate closers kindly read the question thoroughly and refrain from incorrectly marking it as a duplicate.
This question is not a general question about getting the environment name. I am aware of many ways. The question is how to get a value that is guaranteed to be consistent with the value that will eventually be made available from HostingEnvironment.EnvironmentName
This question is about console apps. It is not about web apps, not even if you just figured out how to do this with web apps and you want to tell everyone. There is no Startup.cs involved. Answers that depend on the default web host fail to address the question.
The host builder setup looks like this.
var hostBuilder = Host.CreateDefaultBuilder(args);
hostBuilder
.ConfigureHostConfiguration(configurationBuilder =>
{
configurationBuilder.AddJsonFile("hostsettings.json", optional: true);
configurationBuilder.AddEnvironmentVariables(prefix: "AED_COORDINATOR_");
configurationBuilder.AddCommandLine(args);
})
.ConfigureAppConfiguration(configurationBuilder =>
{
var env = Environment.GetEnvironmentVariable($"{ENV_PREFIX}ENVIRONMENT");
configurationBuilder
.AddJsonFile("appSettings.json", false, true)
.AddJsonFile($"appSettings.{env}.json", true, true);
})
...
With this in launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/bin/Debug/netcoreapp3.1/aed.coordinator.dll",
"args": [
"--environment=Production"
],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"stopAtEntry": false,
"env": {
"AED_COORDINATOR_ENVIRONMENT": "Development"
}
},
running it produces this.
The problem is that appSettings.Development.json is loaded because Environment.GetEnvironmentVariable($"{ENV_PREFIX}ENVIRONMENT") does not take into account the command line arguments.
I am aware that can extend this code to explicitly consider the command line arguments, but reliable parsing of command line arguments is non-trivial and anyway what's the point of having a builder if you have to in-line everything? Worse, they can disagree.
So, is there some way to use the builder (which is already configured in this respect) to resolve the environment?
You can't invoke .Build() more than once so it's not possible to partly configured the builder, construct an intermediate host, pull the resolved environment out of it and then finish configuring.
It is possible to do this.
var ENV_PREFIX = "AED_COORDINATOR_";
string env;
using (var envHost = Host.CreateDefaultBuilder(args).ConfigureHostConfiguration(configurationBuilder =>
{
configurationBuilder.AddJsonFile("hostsettings.json", optional: true);
configurationBuilder.AddEnvironmentVariables(prefix: ENV_PREFIX);
configurationBuilder.AddCommandLine(args);
}).Build())
env = envHost.Services.GetService<IHostEnvironment>().EnvironmentName;
This resolves env in advance and properly disposes builder and intermediate host, and the rest of the code is more or less unchanged.
However, it is not necessary to do it.
In the lambda supplied to hostBuilder.ConfigureServices() I was inspecting the services and found that appSettings.{env}.json is magically added anyway — while the above code is successful, both appSettings.json and appSettings.{env}.json appeared twice as providers — and the host builder used the correct environment, so the entirety of
.ConfigureAppConfiguration(configurationBuilder =>
{
configurationBuilder
.AddJsonFile("appSettings.json", false, true)
.AddJsonFile($"appSettings.{env}.json", true, true);
})
is unnecessary.
Which means that provided you get this part right
.CreateDefaultBuilder(args).ConfigureHostConfiguration(configurationBuilder =>
{
configurationBuilder.AddJsonFile("hostsettings.json", optional: true);
configurationBuilder.AddEnvironmentVariables(prefix: ENV_PREFIX);
configurationBuilder.AddCommandLine(args);
})
you don't need the rest.
Later code can even use the config:
.ConfigureServices((hostContext, services) =>
{
services.AddConfig(hostContext.Configuration);
services.AddHostedService<Worker>();
});
The AddConfig method is an extension method that prepares the options classes for use by dependency injection.
public static IServiceCollection AddConfig(this IServiceCollection services, IConfiguration config)
{
var section = config.GetSection(MosquittoOptions.SectionName);
services.Configure<MosquittoOptions>(section);
section = config.GetSection(ServicesLayerOptions.SectionName);
services.Configure<ServicesLayerOptions>(section);
return services;
}

Elasticsearch repository not allowing default field type

While creating an index Elasticsearch Repository does not allow default type. If field type annotation is missing, assuming default type, the Spring data elasticsearch mapper throws exception and then creates some default mapping when I save the first object.
I'm wondering if it is somehow possible to not annotate every field in of my data objects?
I'm using Spring Data Elasticsearch v3.1.8 and Elasticsearch 6.2.2.
Thanks
There is effectively a way to avoid annoting every fields. Elasticsearch need to create the mapping of the document.
You can indicate to spring how the document need to be mapped with #Field or by providing the mapping configuration.
With spring just annotate the document with #Mapping to set mapping file location.
Also you could just create the mapping using Elasticsearch PUT mapping API.
#Document(indexName = Produit.INDEX, type = ProduitES.TYPE, shards = 1)
#Mapping(mappingPath = "/mappings/mappings-produit.json")
public class Produit {
private String code;
private String name;
...
}
The mapping file in resources/mappings/mappings-produit.json folder :
{
"produit": {
"dynamic": "strict",
"properties": {
"code": {
"type": "text",
},
"name": {
"type": "text",
"index": false
}
}
}
}

How do I change connection string for Update-Database ef migrations?

I am trying to run Update-Database, and I would like to specify the connection string, but the CLI is looking at the wrong one. There are two connection strings in my appsettings.json file:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"LocalWindows": "data source=.\\SQLEXPRESS;initial catalog=Intranet;persist security info=True;integrated security=true;",
"AzureDevelopment": "Server=tcp:en..."
}
}
When I run Update-Database, AzureDevelopment is always the key it uses. So if I copy the LocalWindows connectionstring to AzureDevelopment's value, it updates the correct database. Furthermore, if I delete AzureDevelopment but leave LocalWindows like this:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"LocalWindows": "data source=.\\SQLEXPRESS;initial catalog=Intranet;persist security info=True;integrated security=true;"
}
}
I get:
Value cannot be null.
Parameter name: connectionString
So it seems at some point, the CLI chose to use the AzureDevelopment string, and I can no longer change the key or supply the connection string as an argument.
My question is how does the migrations CLI know what connection string to use? Is it detecting the string through some reflection magic on the startup settings or what? All I see online is how to specify the project when running Update-Database. There used to be -ConnectionString and -ConnectionStringName parameters for the CLI, but those are no longer available.
All I had to do was the following in PowerShell:
$env:ASPNETCORE_ENVIRONMENT='LocalWindows'
dotnet ef database update
or
$env:ASPNETCORE_ENVIRONMENT='LocalWindows'
Update-Database
Turning on verbose with Update-Database -verbose also shows you the environment in the output to make sure it's hitting the correct one.
What doesn't work:
Setting a global ASPNETCORE_ENVIRONMENT environment variable in Windows
Setting the ASPNETCORE_ENVIRONMENT environment variable in the Project->Settings->Debug screen
In EF Core 5.0, it is possible to specify the connection string like this:
dotnet ef database update --connection "<connection string>"

How to disable V2 OData $batch request by default in UI5?

I made a Master-Detail application in Web IDE with SAPUI5.
I connected my application to an OData service (V2). The connection parameters have been stored in manifest.json.
I want to prevent my UI5 application from using $batch requests.
I know how to use the following code to disable batch request for a particular request:
var oDataModel = this.getModel(); // sap.ui.model.odata.v2.ODataModel
oDataModel.setUseBatch(false);
But the problem is that I can not use this in onInit function.
Can I set some parameter in manifest.json to disable batch request in general and even when the program is loading it does not use $batch?
You should be able to add parameter useBatch to the settings of your model. According to the documentation (section /sap.ui5/models) these settings will be passed to the constructor.
{
"sap.ui5": {
"models": {
"yourV2ODataModel": {
"dataSource": "yourDataSource",
"settings": {
"useBatch": false
}
}
}
}
}
The availability of component models in onInit has been discussed here several times. See the application init process to see why they are not available.
Well you could to it in the onInit function. But like this:
var oDataModel = this.getOwnerComponent().getModel();
oDataModel.setUseBatch(false);
Go to Component.js
on its "init" method:
this.getModel("yourDesiredModel").setUseBatch(false)

Resources