-
-
Notifications
You must be signed in to change notification settings - Fork 7k
NestJS server codegen #21494
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
NestJS server codegen #21494
Changes from 9 commits
23450c1
d886d19
eb834cd
1844ae8
a1ddef4
387e96e
d4f8807
07ad56f
ac039c5
cd4c0d6
f55b21f
a81f776
b9c18c1
18ee6ac
b769376
fa06a62
dc89dcc
2f05e15
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# OpenApi Generator _typescript-nestjs-server_ | ||
|
||
Usage: The generated output is intended to be its own module, that can be imported into your NestJS App Module. You do not need to change generated files, just import the module and implement the API | ||
|
||
Example usage (with the openapi sample `petstore.yaml`): | ||
|
||
1. Invoke openapi-generator | ||
``` | ||
openapi-generator-cli.jar generate -i petstore.yaml -g typescript-nestjs-server -o api-module/ | ||
``` | ||
2. implement the contracts from `api-module/api` | ||
|
||
`handlers/PetService.ts`: | ||
```typescript | ||
import { Pet, ApiResponse } from "models"; | ||
import { Observable } from "rxjs"; | ||
import { PetApi } from "../api"; | ||
import { Inject, Injectable } from "@nestjs/common"; | ||
|
||
@Injectable() | ||
export class PetService implements PetApi { | ||
addPet(pet: Pet, request: Request): Pet | Promise<Pet> | Observable<Pet> { | ||
throw new Error("Method not implemented."); | ||
} | ||
|
||
deletePet(petId: number, apiKey: string, request: Request): void | Promise<void> | Observable<void> { | ||
throw new Error("Method not implemented."); | ||
} | ||
|
||
... | ||
``` | ||
|
||
3. Import the API Module with a reference to your implementation | ||
`app.module.ts` | ||
```typescript | ||
import { Module } from "@nestjs/common"; | ||
import { ApiModule } from "api-module/api.module"; | ||
import { PetService } from "./handlers/PetService"; | ||
import { UserService } from "./handlers/UserService"; | ||
import { StoreService } from "./handlers/StoreService"; | ||
|
||
@Module({ | ||
imports: [ | ||
ApiModule.forRoot({ | ||
petApi: PetService, | ||
userApi: UserService, | ||
storeApi: StoreService | ||
}), | ||
], | ||
controllers: [], | ||
providers: [], | ||
}) | ||
export class AppModule {} | ||
``` | ||
|
||
You now can regenerate the API module as often as you want without overriding your implementation. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Type } from '@nestjs/common'; | ||
{{#apiInfo}} | ||
{{#apis}} | ||
{{#operations}} | ||
import { {{classname}} } from '{{apiPackage}}'; | ||
{{/operations}} | ||
{{/apis}} | ||
|
||
export type ApiImplementations = { | ||
{{#apis}} | ||
{{#operations}} | ||
{{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}: Type<{{classname}}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how is the implementer supposed to use this? can you clarify that in the PR description? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I updated the description as well as the committed README |
||
{{/operations}} | ||
{{/apis}} | ||
}; | ||
{{/apiInfo}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { DynamicModule, Module, Provider } from '@nestjs/common'; | ||
import { ApiImplementations } from './api-implementations' | ||
{{#apiInfo}} | ||
{{#apis}} | ||
import { {{classname}} } from './{{apiPackage}}'; | ||
import { {{classname}}Controller } from './controllers'; | ||
{{/apis}} | ||
{{/apiInfo}} | ||
|
||
@Module({}) | ||
export class ApiModule { | ||
static forRoot(apiImplementations: ApiImplementations): DynamicModule { | ||
const providers: Provider[] = [ | ||
{{#apiInfo}} | ||
{{#apis}} | ||
{ | ||
provide: {{classname}}, | ||
useClass: apiImplementations.{{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}} | ||
}, | ||
|
||
aryobenholzner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{{/apis}} | ||
{{/apiInfo}} | ||
]; | ||
|
||
return { | ||
module: ApiModule, | ||
controllers: [ | ||
{{#apiInfo}} | ||
{{#apis}} | ||
{{classname}}Controller, | ||
{{/apis}} | ||
{{/apiInfo}} | ||
], | ||
providers: [...providers], | ||
exports: [...providers] | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
aryobenholzner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import { Observable } from 'rxjs'; | ||
import { {{#tsImports}}{{classname}}, {{/tsImports}} } from '../{{modelPackage}}'; | ||
|
||
@Injectable() | ||
export abstract class {{classname}} { | ||
{{#operations}} | ||
{{#operation}} | ||
abstract {{operationId}}({{#allParams}}{{paramName}}: {{{dataType}}}, {{/allParams}} request: Request): {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} | Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}> | Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}>; | ||
|
||
{{/operation}} | ||
{{/operations}} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{{#apiInfo}} | ||
{{#apis}} | ||
{{#operations}} | ||
export * from './{{classFilename}}'; | ||
{{/operations}} | ||
{{/apis}} | ||
{{/apiInfo}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Controller{{#httpMethods}}, {{.}}{{/httpMethods}}, Req } from '@nestjs/common'; | ||
import { Observable } from 'rxjs'; | ||
import { {{classname}} } from '../{{apiPackage}}'; | ||
import { {{#tsImports}}{{classname}}, {{/tsImports}} } from '../{{modelPackage}}'; | ||
|
||
@Controller() | ||
export class {{classname}}Controller { | ||
constructor(private readonly {{classVarName}}: {{classname}}) {} | ||
|
||
{{#operations}} | ||
{{#operation}} | ||
@{{#vendorExtensions.x-http-method}}{{.}}{{/vendorExtensions.x-http-method}}{{^vendorExtensions.x-http-method}}{{httpMethod}}{{/vendorExtensions.x-http-method}}('{{path}}') | ||
{{operationId}}({{#allParams}}{{paramName}}: {{{dataType}}}, {{/allParams}}@Req() request: Request): {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} | Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}> | Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}> { | ||
return this.{{classVarName}}.{{operationId}}({{#allParams}}{{paramName}}, {{/allParams}} request); | ||
} | ||
|
||
{{/operation}} | ||
{{/operations}} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{{#apiInfo}} | ||
{{#apis}} | ||
{{#operations}} | ||
export * from './{{classFilename}}.controller'; | ||
{{/operations}} | ||
{{/apis}} | ||
{{/apiInfo}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#!/bin/bash | ||
|
||
# Git push script for {{npmName}} | ||
|
||
# Check if we're in a git repository | ||
if ! git rev-parse --git-dir > /dev/null 2>&1; then | ||
echo "Error: Not in a git repository" | ||
exit 1 | ||
fi | ||
|
||
# Get the current branch | ||
CURRENT_BRANCH=$(git branch --show-current) | ||
|
||
echo "Pushing to git repository..." | ||
echo "Current branch: $CURRENT_BRANCH" | ||
|
||
# Add all changes | ||
git add . | ||
|
||
# Commit with a default message if no commit message provided | ||
if [ -z "$1" ]; then | ||
git commit -m "Update generated NestJS server code" | ||
else | ||
git commit -m "$1" | ||
fi | ||
|
||
# Push to the current branch | ||
git push origin $CURRENT_BRANCH | ||
|
||
echo "Successfully pushed to git repository!" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# compiled output | ||
/dist | ||
/node_modules | ||
|
||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
pnpm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
lerna-debug.log* | ||
|
||
# OS | ||
.DS_Store | ||
|
||
# Tests | ||
/coverage | ||
/.nyc_output | ||
|
||
# IDEs and editors | ||
/.idea | ||
.project | ||
.classpath | ||
.c9/ | ||
*.launch | ||
.settings/ | ||
*.sublime-workspace | ||
|
||
# IDE - VSCode | ||
.vscode/* | ||
!.vscode/settings.json | ||
!.vscode/tasks.json | ||
!.vscode/launch.json | ||
!.vscode/extensions.json | ||
|
||
# dotenv environment variable files | ||
.env | ||
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
.env.local | ||
|
||
# parcel-bundler cache (https://parceljs.org/) | ||
.cache | ||
.parcel-cache | ||
|
||
# Next.js build output | ||
.next | ||
|
||
# Nuxt.js build / generate output | ||
.nuxt | ||
dist | ||
|
||
# Storybook build outputs | ||
.out | ||
.storybook-out | ||
|
||
# Temporary folders | ||
tmp/ | ||
temp/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{{#models}} | ||
{{#model}} | ||
{{#tsImports}} | ||
import { {{classname}} } from './{{filename}}'; | ||
{{/tsImports}} | ||
|
||
|
||
{{#description}} | ||
/** | ||
* {{{.}}} | ||
*/ | ||
{{/description}} | ||
{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{#isAlias}}{{>modelAlias}}{{/isAlias}}{{^isAlias}}{{#taggedUnions}}{{>modelTaggedUnion}}{{/taggedUnions}}{{^taggedUnions}}{{#oneOf}}{{#-first}}{{>modelOneOf}}{{/-first}}{{/oneOf}}{{^oneOf}}{{>modelGeneric}}{{/oneOf}}{{/taggedUnions}}{{/isAlias}}{{/isEnum}} | ||
{{/model}} | ||
{{/models}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export type {{classname}} = {{dataType}}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{{#stringEnums}} | ||
export enum {{classname}} { | ||
{{#allowableValues}} | ||
{{#enumVars}} | ||
{{#enumDescription}} | ||
|
||
/** | ||
* {{.}} | ||
*/{{/enumDescription}} | ||
{{name}} = {{{value}}}{{^-last}},{{/-last}} | ||
{{/enumVars}} | ||
{{/allowableValues}} | ||
} | ||
{{/stringEnums}} | ||
{{^stringEnums}} | ||
export const {{classname}} = { | ||
{{#allowableValues}} | ||
{{#enumVars}} | ||
{{#enumDescription}} | ||
|
||
/** | ||
* {{.}} | ||
*/ | ||
{{/enumDescription}} | ||
{{name}}: {{{value}}}{{^-last}},{{/-last}} | ||
{{/enumVars}} | ||
{{/allowableValues}} | ||
} as const; | ||
export type {{classname}} = typeof {{classname}}[keyof typeof {{classname}}]; | ||
{{/stringEnums}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
export interface {{classname}}{{#allParents}}{{#-first}} extends {{/-first}}{{{.}}}{{^-last}}, {{/-last}}{{/allParents}} { {{>modelGenericAdditionalProperties}} | ||
{{#vars}} | ||
{{#description}} | ||
/** | ||
* {{{description}}} | ||
{{#deprecated}} | ||
* @deprecated | ||
{{/deprecated}} | ||
*/ | ||
{{/description}} | ||
{{^description}} | ||
{{#deprecated}} | ||
/** @deprecated */ | ||
{{/deprecated}} | ||
{{/description}} | ||
{{^modelPropertyNamingOriginal}} | ||
{{#isReadOnly}}readonly {{/isReadOnly}}{{{name}}}{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}} | null{{/isNullable}}; | ||
{{/modelPropertyNamingOriginal}} | ||
{{#modelPropertyNamingOriginal}} | ||
{{#isReadOnly}}readonly {{/isReadOnly}}{{#hasSanitizedName}}'{{{baseName}}}'{{/hasSanitizedName}}{{^hasSanitizedName}}{{{name}}}{{/hasSanitizedName}}{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}} | null{{/isNullable}}; | ||
{{/modelPropertyNamingOriginal}} | ||
{{/vars}} | ||
}{{>modelGenericEnums}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{{#additionalPropertiesType}} | ||
|
||
[key: string]: {{{additionalPropertiesType}}}{{#hasVars}} | any{{/hasVars}}; | ||
|
||
{{/additionalPropertiesType}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{{#hasEnums}} | ||
|
||
{{^stringEnums}} | ||
export namespace {{classname}} { | ||
{{/stringEnums}} | ||
{{#vars}} | ||
{{#isEnum}} | ||
{{#stringEnums}} | ||
export enum {{classname}}{{enumName}} { | ||
{{#allowableValues}} | ||
{{#enumVars}} | ||
{{name}} = {{{value}}}{{^-last}},{{/-last}} | ||
{{/enumVars}} | ||
{{/allowableValues}} | ||
}; | ||
{{/stringEnums}} | ||
{{^stringEnums}} | ||
export const {{enumName}} = { | ||
{{#allowableValues}} | ||
{{#enumVars}} | ||
{{name}}: {{{value}}}{{^-last}},{{/-last}} | ||
{{/enumVars}} | ||
{{/allowableValues}} | ||
} as const; | ||
export type {{enumName}} = typeof {{enumName}}[keyof typeof {{enumName}}]; | ||
{{/stringEnums}} | ||
{{/isEnum}} | ||
{{/vars}} | ||
{{^stringEnums}}}{{/stringEnums}} | ||
{{/hasEnums}} |
Uh oh!
There was an error while loading. Please reload this page.