Skip to content

[typescript-nestjs] Add Nestjs Generator#5518

Merged
wing328 merged 15 commits intoOpenAPITools:typescript-nextjsfrom
vfrank66:master
Jan 24, 2021
Merged

[typescript-nestjs] Add Nestjs Generator#5518
wing328 merged 15 commits intoOpenAPITools:typescript-nextjsfrom
vfrank66:master

Conversation

@vfrank66
Copy link
Copy Markdown

@vfrank66 vfrank66 commented Mar 4, 2020

fixes #3336 adding nestjs generator

PR checklist

  • Read the contribution guidelines.
  • If contributing template-only or documentation-only changes which will change sample output, build the project before.
  • Run the shell script(s) under ./bin/ (or Windows batch scripts under.\bin\windows) to update Petstore samples related to your fix. This is important, as CI jobs will verify all generator outputs of your HEAD commit, and these must match the expectations made by your contribution. You only need to run ./bin/{LANG}-petstore.sh, ./bin/openapi3/{LANG}-petstore.sh if updating the code or mustache templates for a language ({LANG}) (e.g. php, ruby, python, etc).
  • File the PR against the correct branch: master, 4.3.x, 5.0.x. Default: master.
  • Copy the technical committee to review the pull request if your PR is targeting a particular programming language.

@TiFu (2017/07) @taxpon (2017/07) @sebastianhaas (2017/07) @kenisteward (2017/07) @Vrolijkx (2017/09) @macjohnny (2018/01) @nicokoenig (2018/09) @topce (2018/10) @akehir (2019/07) @petejohansonxo (2019/11) @amakhrov (2020/02)

Copy link
Copy Markdown
Member

@macjohnny macjohnny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for your contribution!
please generate the nestjs samples and remove the unrelated groovy and kotlin sample changes.


@Global
@Module({
imports: [ HttpModule ],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this import necessary? shouldn't the consumer import this on a global level?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the HttpModule is used as a static module so yes it can be, but I actually should probably change it to a dynamic module with HttpModule.register({})

@@ -0,0 +1,4 @@
wwwroot/*.js
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this file should be named .gitignore instead of gitignore

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why but the standard is to keep the name gitignore and then rename is the codegen supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore")); this is done is all typescript generators. Maybe it is something with git idk

};
{{/stringEnums}}
{{^stringEnums}}
export type {{enumName}} = {{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}} | {{/-last}}{{/enumVars}}{{/allowableValues}};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the indentation correct?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking into

"name": "{{{npmName}}}",
"version": "{{{npmVersion}}}",
"description": "swagger client for {{{npmName}}}",
"author": "Swagger Codegen Contributors",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"author": "Swagger Codegen Contributors",
"author": "OpenAPI Generator Contributors",

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

{
"name": "{{{npmName}}}",
"version": "{{{npmVersion}}}",
"description": "swagger client for {{{npmName}}}",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"description": "swagger client for {{{npmName}}}",
"description": "REST client for {{{npmName}}}",

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -0,0 +1,49 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Copyright 2018 SmartBear Software

@@ -0,0 +1,49 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Copyright 2018 SmartBear Software

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -0,0 +1,603 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Copyright 2018 SmartBear Software

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 although not sure why i should remove this a lot if not all the other codegens have this.

import static groovyx.net.http.HttpBuilder.configure
import static java.net.URI.create

class ApiUtils {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the groovy files are unrelated to this PR?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for some reason building the projects creates all these groovy files, idk what is going on

@@ -0,0 +1,192 @@
/**
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the kotlin files are unrelated to this PR

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as the groovy

@@ -0,0 +1,31 @@
#!/bin/sh
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please also add an entry to

"${root}/bin/typescript-rxjs-petstore-all.sh"

Copy link
Copy Markdown
Author

@vfrank66 vfrank66 Sep 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@macjohnny Im sorry I don't understand this.

@macjohnny macjohnny changed the title Issue 3336 Add Nestjs Generator [typescript-nestjs] Add Nestjs Generator Mar 4, 2020
@macjohnny macjohnny added this to the 4.3.0 milestone Mar 4, 2020
Copy link
Copy Markdown
Contributor

@amakhrov amakhrov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!
It looks like the generator is heavily based on the existing angular generator. I feel it needs another pass or two to clean up all the code that is only relevant to angular but not nestjs.

As a very side note. Unless nestjs requires some custom data / formatting that is not currently provided in typescript angular or other typescript generators (I'm not sure I can see such customizations in this PR) - you could achieve your goal by creating your own set of templates and passing them to one of the existing generators (via --template-dir cli argument). This would eliminate the need in a brand new generator and could save you significant amount of efforts.

Comment thread docs/generators/typescript-nestjs.md Outdated
|npmRepository|Use this property to set an url your private npmRepo in the package.json| |null|
|withInterfaces|Setting this property to true will generate interfaces next to the default class implementations.| |false|
|taggedUnions|Use discriminators to create tagged unions instead of extending interfaces.| |false|
|providedInRoot|Use this property to provide Injectables in root (it is only valid in nestjs version greater or equal to 6.0.0).| |false|
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please clarify how this option is used in the generated code?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not used and should be removed!

this.cliOptions.add(new CliOption(MODEL_SUFFIX, "The suffix of the generated model."));
this.cliOptions.add(new CliOption(MODEL_FILE_SUFFIX, "The suffix of the file of the generated model (model<suffix>.ts)."));
this.cliOptions.add(new CliOption(FILE_NAMING, "Naming convention for the output files: 'camelCase', 'kebab-case'.").defaultValue(this.fileNaming));
this.cliOptions.add(new CliOption(STRING_ENUMS, STRING_ENUMS_DESC).defaultValue(String.valueOf(this.stringEnums)));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these cli options duplicate the ones defined in the parent class. Is there a particular reason to duplicate it here also?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot find the duplication, link?

additionalProperties.put("injectionToken", nestVersion.atLeast("4.0.0") ? "InjectionToken" : "OpaqueToken");
additionalProperties.put("injectionTokenTyped", nestVersion.atLeast("4.0.0"));
additionalProperties.put("useHttpClient", nestVersion.atLeast("4.3.0"));
additionalProperties.put("useRxJS6", nestVersion.atLeast("6.0.0"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this logic was copied from the Angular generator. Does it apply to Nest framework with exactly same version numbers?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No this line should be deleted

} else {
// Nestjs v2-v4 requires typescript ">=2.1.5 <2.8"
additionalProperties.put("tsVersion", ">=2.1.5 <2.8.0");
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a good reason to support old framework versions? Do you plan to use this generate in projects with old Nestjs?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problems, will hardcode

op.httpMethod = op.httpMethod.toLowerCase(Locale.ENGLISH);
} else {
// Convert httpMethod to Nestjs's RequestMethod enum
// https://nestjs.io/docs/ts/latest/api/http/index/RequestMethod-enum.html
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

broken link - seems to be copied from angular.
is this logic applicable to nestjs anyway?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does not apply

Copy link
Copy Markdown

@quezak quezak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disclaimer: I'm not a contributor here (at least not yet 😄), and I'm not familiar with the java codebase. But I have experience with Nest.js, so I'm dropping a few comments from that perspective. And I've been watching the issue for some time now, so I'm just curious how will it turn out 😃

I've added some nitpicks (like others already mentioned, some angular-related stuff needs to be cleaned up), plus one more serious issue about having multiple generated modules imported in one app. I'll try to build the generator and see what's the output for the APIs that I'm using, I'll come back with more feedback if I find anything interesting.

Comment thread docs/generators.md Outdated

## CLIENT generators
* [ada](generators/ada.md)
## CLIENT generators* [ada](generators/ada.md)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accidentally deleted newline?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it's definitely a coincidence.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +76 to +82
@Module({
imports: [ ApiModule.forRoot(apiConfigFactory) ],
declarations: [ AppComponent ],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule {}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this (and IDK how much more of this file) looks copied from angular and is not applicable to nest :)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First part about creating a local package yes if you wanted to but ill remove. This part is is and below all apply.

Comment on lines +11 to +13
@Global
@Module({
imports: [ HttpModule ],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is my main comment for this PR.

  1. Why is the module named ApiModule? In my project, which isn't too large, I already have 8 different openapi-generated clients to connect to various 3rd party services, so I think the module should have a specific name.
  2. Why is the module global? Did you maybe want to mark the forRoot dynamic module global instead? This way you'd import ApiModule.forRoot(...) in AppModule globally, to provide the Configuration in one place, and then import the plain ApiModule just in the modules that want to use the generated API client. If that's not the case, can you please show me a minimal example how do you intend this module to be used, so I can understand it better?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the naming conflict can be avoided with renamed imports, see also #4101

Copy link
Copy Markdown

@quezak quezak Mar 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imports can be renamed and it's not the problem -- what I'm worried is that the class name becomes the service/module's token in Nest's dependency injection system. I don't know precisely what will happen if you register two Nest modules/providers under the same name, but it most likely won't work. Example: the generated API clients inject the Configuration provider and the BASE_PATH value, which will be ambiguous since they are registered globally for all imported ApiModules.

I see it actually was fixed in Nest for module classes, but:

  • the fix was made in a relatively recent Nest version (6.10),
  • the fix handles module classes, so provider classes (like Configuration here) may still not work
  • IMHO it's just a bad practice, since it's very likely to import multiple different ApiModules in one app, so it decreases code readability and forces you to manually rename imports every time.
  • note that the BASE_PATH injected config I mentioned in my other comment is a manually passed DI token, so it will always be ambiguous.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, so this is a bit different from the angular case.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@quezak

  1. Because that was a consistent name, the folder structure and the import as give a precise name. Although the cli could have an optional name to specify what you would like. This PR did not seem like the time to work out other enhancements.
  2. Global so that a consumer does not have to add the granularity which you are suggesting. The use I am using this fork .jar to codege for is one app initailization in a AWS lambda function. I do not need the granularity you suggest.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@quezak class names do not become the Nestjs DI token because they are dynamic modules due to .forRoot(), if they did not have .forRoot() it would be a static module

Configuration and BASE_PATH as seen in the example readme are set by the factory pattern and not a problem as you are possibly stating.

public static forRoot(configurationFactory: () => Configuration): DynamicModule {
return {
module: ApiModule,
providers: [ { provide: Configuration, useFactory: configurationFactory } ]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as (1.) here: if this is just named Configuration, won't the injection break if you import multiple generated modules for different APIs? Also, what if you already have a service named Configuration in your app (which seems likely), won't this break the DI?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If classes are defined in different files (even with the same class name) - these are distinct class references from the JS perspective.
So if Nestjs uses this reference as an injection token (rather than, say, the string name of the class, then there should be no conflicts for DI.
E.g. Angular uses actual class reference for DI, not a name - so it's not an issue there.

Would you be willing to investigate how Nestjs DI works and post a comment in this PR? It can help with defining the direction for further changes

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@quezak No it will not break injection

Comment on lines +36 to +37
if (!httpService) {
throw new Error('You need to import the {HttpModule in your AppModule!');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this check needed, if the ApiModule explicitly imports HttpModule?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, should not be here

public defaultHeaders = new Map()
public configuration = new Configuration();

constructor(protected httpClient: HttpService, @Inject('BASE_PATH') basePath: string, configuration: Configuration) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BASE_PATH DI token will also be ambiguous if you have multiple generated clients in the project. We probably want to give it a more specific and unique name, like _OPENAPI_GENERATED_{{apiName}}_BASE_PATH, so it doesn't collide with any DI tokens that the users might already have in their Nest apps.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's a brand new generator with no need for backward compatibility, I would suggest getting rid of a dedicated "BASE_PATH" injection token altogether - in favor of Configuration (which also includes basePath)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amakhrov I agree with that makes sense

Comment on lines +50 to +56
const form = 'multipart/form-data';
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const form = 'multipart/form-data';
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
const form = 'multipart/form-data';
return consumes.includes(form);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


// Set the typescript version compatible to the Nestjs version
if (nestVersion.atLeast("6.0.0")) {
additionalProperties.put("tsVersion", ">=3.4.0 <3.6.0");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why <3.6.0? We're successfully running Nest 6 with TS 3.7.5 and I'm not aware of any requirements that would limit the version to <3.6.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed set to ">=3.4.0 <4.0.0"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, does it break with 4.0? :D (if not, why use max version limit?)

@quezak
Copy link
Copy Markdown

quezak commented Mar 5, 2020

@amakhrov re Nest's management of same-name services: I've built a quick example and confirmed my version.

TL;DR: Nest.js indeed uses class names for DI tokens, so the generated classes (injected in the same scope) should have unique names. Full example below.

Note1: it could possibly work for Configuration if it was only registered internally in the module, but it's registered globally if I understand the design correctly.

Note2: even if it worked correctly, I still personally think it would be bad for DX and leading to confusing errors to export a non-meaningful ambiguous names like ApiModule and Configuration. As mentioned, in my project I use already 8 different generated API clients, and I'd have to take extra care each time importing them, to see if the import line inserted by my editor is from some/long/path/to/generated/files/api1/ or some/long/path/to/generated/files/api2/, while normally I never have to even look at the imports.


Example test service to be injected

// dir1/test.service.ts
@Injectable()
export class TestService {
    foo(): number { return 1; }
}

// dir1/test.module.ts
@Module({
    providers: [TestService],
    exports: [TestService],
})
export class TestModule {}

// dir2/test.module.ts copied
// dir2/test.service.ts copied, only `foo()` returns `2`

Example usage 1:

// a consumer module
import { TestModule as TestModule1 } from 'dir1/test.module';
import { TestModule as TestModule2 } from 'dir1/test.module';
@Module({ imports: [TestModule1, TestModule2] })
export class ConsumerModule {}

// a consumer service
import { TestService } from 'dir1/test.service'
@Injectable()
export class ConsumerService {
    constructor(testService: TestService) {
        console.log('foo:', testService.foo());
    }
}

result: console outputs foo: 2, even though I've imported TestService from dir1 which should return 1.

Example usage 2:

// a consumer module
import { TestModule } from 'dir2/test.module';
@Module({ imports: [TestModule] })
export class ConsumerModule {}

// a consumer service
import { TestService } from 'dir1/test.service'
@Injectable()
export class ConsumerService {
    constructor(testService: TestService) {
        console.log('foo:', testService.foo());
    }
}

result: console outputs foo: 2, even though I've injected the TestService imported from dir1, while the module from dir1 is not even loaded into DI.


@wing328 wing328 modified the milestones: 4.3.0, 4.3.1 Mar 27, 2020
@wing328 wing328 removed this from the 4.3.1 milestone May 6, 2020
@macjohnny
Copy link
Copy Markdown
Member

@vfrank66 any chance to get this into 5.0.0?

@vfrank66
Copy link
Copy Markdown
Author

vfrank66 commented Jun 5, 2020

@macjohnny let me free up some time within the next 7 days to get back on this and fix all the current problems and then start address the questions, concerns here. Sorry for the delay I have been use a compiled jar of this code within nestjs projects for the post couple months and haven't come back to make sure it is the official release.

@manchuwook
Copy link
Copy Markdown

@macjohnny let me free up some time within the next 7 days to get back on this and fix all the current problems and then start address the questions, concerns here. Sorry for the delay I have been use a compiled jar of this code within nestjs projects for the post couple months and haven't come back to make sure it is the official release.

Do you have this compiled jar as a release on your fork? I have a fairly elaborate schema that I'd like to use NestJs for.

@wing328
Copy link
Copy Markdown
Member

wing328 commented Aug 17, 2020

@vfrank66 is there anything we can help you with this PR? e.g. resolving merge conflicts?

@Vmarci94
Copy link
Copy Markdown

Vmarci94 commented Sep 1, 2020

@vfrank66 is there anything we can help you with this PR? e.g. resolving merge conflicts?

Hi, this feature would come in handy for my work.
I tried it and it works well for me.
Can I help the project progress?

@Asafkbalink
Copy link
Copy Markdown

Hey, this is hanging here for a pretty long time already - anything I can do to help? What is missing in order to have it merged?

@quezak
Copy link
Copy Markdown

quezak commented Sep 9, 2020

Hey, this is hanging here for a pretty long time already - anything I can do to help? What is missing in order to have it merged?

there are some pretty serious (imo) unresolved review comments :)

@vfrank66
Copy link
Copy Markdown
Author

@amakhrov re Nest's management of same-name services: I've built a quick example and confirmed my version.

TL;DR: Nest.js indeed uses class names for DI tokens, so the generated classes (injected in the same scope) should have unique names. Full example below.

Note1: it could possibly work for Configuration if it was only registered internally in the module, but it's registered globally if I understand the design correctly.

Note2: even if it worked correctly, I still personally think it would be bad for DX and leading to confusing errors to export a non-meaningful ambiguous names like ApiModule and Configuration. As mentioned, in my project I use already 8 different generated API clients, and I'd have to take extra care each time importing them, to see if the import line inserted by my editor is from some/long/path/to/generated/files/api1/ or some/long/path/to/generated/files/api2/, while normally I never have to even look at the imports.

Example test service to be injected

// dir1/test.service.ts
@Injectable()
export class TestService {
    foo(): number { return 1; }
}

// dir1/test.module.ts
@Module({
    providers: [TestService],
    exports: [TestService],
})
export class TestModule {}

// dir2/test.module.ts copied
// dir2/test.service.ts copied, only `foo()` returns `2`

Example usage 1:

// a consumer module
import { TestModule as TestModule1 } from 'dir1/test.module';
import { TestModule as TestModule2 } from 'dir1/test.module';
@Module({ imports: [TestModule1, TestModule2] })
export class ConsumerModule {}

// a consumer service
import { TestService } from 'dir1/test.service'
@Injectable()
export class ConsumerService {
    constructor(testService: TestService) {
        console.log('foo:', testService.foo());
    }
}

result: console outputs foo: 2, even though I've imported TestService from dir1 which should return 1.

Example usage 2:

// a consumer module
import { TestModule } from 'dir2/test.module';
@Module({ imports: [TestModule] })
export class ConsumerModule {}

// a consumer service
import { TestService } from 'dir1/test.service'
@Injectable()
export class ConsumerService {
    constructor(testService: TestService) {
        console.log('foo:', testService.foo());
    }
}

result: console outputs foo: 2, even though I've injected the TestService imported from dir1, while the module from dir1 is not even loaded into DI.

This is not valid, your example is not a dynamic module it is a static module. That is different than the generator ApiModule.forRoot(...) in nestjs

@vfrank66
Copy link
Copy Markdown
Author

@quezak check out nestjs/nest#1632

@quezak
Copy link
Copy Markdown

quezak commented Sep 12, 2020

@quezak check out nestjs/nest#1632

@vfrank66 can you please provide a full example of how a module generated with this would be used in a Nest app? Ideally with two different generated modules used in one app. I'm trying to understand the approach here as it looks different than what we're used to.

Comment thread docs/generators.md Outdated

## CLIENT generators
* [ada](generators/ada.md)
## CLIENT generators* [ada](generators/ada.md)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it's definitely a coincidence.


@Override
protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) {
codegenModel.additionalPropertiesType = getTypeDeclaration(ModelUtils.getAdditionalProperties(schema));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use de base getAdditionalProperties function!

* Finds and returns a path parameter of an operation by its name
*
* @param operation the operation
* @param operation the operation
Copy link
Copy Markdown

@Asafkbalink Asafkbalink Sep 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param operation the operation
* @param operation the operation

@manchuwook
Copy link
Copy Markdown

Can you, at the absolute least, get this to Experimental? Are there any other devs that can pull this in and work on it? @vfrank66 seems to be the only one who can access and make changes.

@macjohnny
Copy link
Copy Markdown
Member

@manchuwook it would be nice to merge the current state as is with an experimental flag. if you want, you can fork the repo of @vfrank66, fix the CI, and create a separate PR.

@wing328
Copy link
Copy Markdown
Member

wing328 commented Jan 21, 2021

In the coming weekend, I'll try to merge this into a branch e.g. typescript-nestjs and resolve the merge conflicts as many things have changed since this PR was first filed. Then we'll see how we can move forward with this new generator (e.g. release as experimental)

@wing328 wing328 changed the base branch from master to typescript-nextjs January 24, 2021 01:49
@wing328 wing328 merged commit 489f58a into OpenAPITools:typescript-nextjs Jan 24, 2021
@msqaddura
Copy link
Copy Markdown

So what was the conclusion here?
how do i use this feature, in desperate need lets say :D

@macjohnny
Copy link
Copy Markdown
Member

this PR was merged in #8522

to use it, you can use the current snapshot version or wait for the 5.0.1 release

@msqaddura
Copy link
Copy Markdown

msqaddura commented Feb 4, 2021

@macjohnny

$ java -jar openapi-generator-cli-6.0.0-20201221.092151-1.jar version
6.0.0-SNAPSHOT

I tried this
$ java -jar openapi-generator-cli-6.0.0-20201221.092151-1.jar generate -i MYOPENAPI.yaml -g typescript-nestjs -o /MYOUTPUT
[error] Check the spelling of the generator's name and try again.

if i try this;
$ java -jar openapi-generator-cli-6.0.0-20201221.092151-1.jar list

I cant find nestjs

@msqaddura
Copy link
Copy Markdown

msqaddura commented Feb 4, 2021

@macjohnny, I will re-explain
image
I tried for all of those this command

$ java -jar openapi-generator-cli-5.1.0-20201221.091745-1.jar list | grep "typescript"
    - typescript (experimental)
    - typescript-angular
    - typescript-aurelia
    - typescript-axios
    - typescript-fetch
    - typescript-inversify
    - typescript-jquery
    - typescript-node
    - typescript-redux-query
    - typescript-rxjs

none of the snapshots has typescript-nestjs

most probably a missing import in the code

@macjohnny
Copy link
Copy Markdown
Member

@msqaddura do you want to fix this?

@wing328
Copy link
Copy Markdown
Member

wing328 commented Feb 4, 2021

I tested with https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/5.0.1-SNAPSHOT/openapi-generator-cli-5.0.1-20210204.092149-93.jar and it works for me:

java -jar openapi-generator-cli.jar generate -g typescript-nestjs -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -o /tmp/test/

@wing328 wing328 added this to the 5.0.1 milestone Feb 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REQ] Add New Language Support for Typescript Nestjs

10 participants