From 1ba38d6a5cbf81b7b2ce5945fd481eec74ff3298 Mon Sep 17 00:00:00 2001 From: William Cheng Date: Tue, 5 Nov 2019 13:54:44 +0800 Subject: [PATCH] add TS server --- bin/typescript-server-petstore.sh | 32 +++ bin/windows/typescript-server-petstore.bat | 14 ++ .../languages/TypeScriptServerCodegen.java | 201 +++++++++++++++++ .../org.openapitools.codegen.CodegenConfig | 1 + .../typescript-server/README.mustache | 87 ++++++++ .../typescript-server/apis.index.mustache | 7 + .../resources/typescript-server/apis.mustache | 204 ++++++++++++++++++ .../resources/typescript-server/gitignore | 4 + .../typescript-server/index.mustache | 3 + .../typescript-server/licenseInfo.mustache | 11 + .../typescript-server/modelEnum.mustache | 12 ++ .../typescript-server/modelGeneric.mustache | 43 ++++ .../typescript-server/modelOneOf.mustache | 14 ++ .../typescript-server/models.index.mustache | 5 + .../typescript-server/models.mustache | 7 + .../typescript-server/package.mustache | 23 ++ .../typescript-server/runtime.mustache | 183 ++++++++++++++++ .../typescript-server/tsconfig.mustache | 23 ++ .../petstore/typescript-server/.gitignore | 4 + .../.openapi-generator-ignore | 23 ++ .../.openapi-generator/VERSION | 1 + .../petstore/typescript-server/apis/PetApi.ts | 194 +++++++++++++++++ .../typescript-server/apis/StoreApi.ts | 87 ++++++++ .../typescript-server/apis/UserApi.ts | 164 ++++++++++++++ .../petstore/typescript-server/apis/index.ts | 3 + .../petstore/typescript-server/index.ts | 3 + .../typescript-server/models/ApiResponse.ts | 35 +++ .../typescript-server/models/Category.ts | 30 +++ .../typescript-server/models/Order.ts | 59 +++++ .../petstore/typescript-server/models/Pet.ts | 59 +++++ .../petstore/typescript-server/models/Tag.ts | 30 +++ .../petstore/typescript-server/models/User.ts | 61 ++++++ .../typescript-server/models/index.ts | 6 + .../petstore/typescript-server/runtime.ts | 194 +++++++++++++++++ .../petstore/typescript-server/tsconfig.json | 21 ++ 35 files changed, 1848 insertions(+) create mode 100755 bin/typescript-server-petstore.sh create mode 100644 bin/windows/typescript-server-petstore.bat create mode 100644 modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptServerCodegen.java create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/README.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/apis.index.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/apis.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/gitignore create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/index.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/licenseInfo.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/modelEnum.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/modelGeneric.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/modelOneOf.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/models.index.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/models.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/package.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/runtime.mustache create mode 100644 modules/openapi-generator/src/main/resources/typescript-server/tsconfig.mustache create mode 100644 samples/server/petstore/typescript-server/.gitignore create mode 100644 samples/server/petstore/typescript-server/.openapi-generator-ignore create mode 100644 samples/server/petstore/typescript-server/.openapi-generator/VERSION create mode 100644 samples/server/petstore/typescript-server/apis/PetApi.ts create mode 100644 samples/server/petstore/typescript-server/apis/StoreApi.ts create mode 100644 samples/server/petstore/typescript-server/apis/UserApi.ts create mode 100644 samples/server/petstore/typescript-server/apis/index.ts create mode 100644 samples/server/petstore/typescript-server/index.ts create mode 100644 samples/server/petstore/typescript-server/models/ApiResponse.ts create mode 100644 samples/server/petstore/typescript-server/models/Category.ts create mode 100644 samples/server/petstore/typescript-server/models/Order.ts create mode 100644 samples/server/petstore/typescript-server/models/Pet.ts create mode 100644 samples/server/petstore/typescript-server/models/Tag.ts create mode 100644 samples/server/petstore/typescript-server/models/User.ts create mode 100644 samples/server/petstore/typescript-server/models/index.ts create mode 100644 samples/server/petstore/typescript-server/runtime.ts create mode 100644 samples/server/petstore/typescript-server/tsconfig.json diff --git a/bin/typescript-server-petstore.sh b/bin/typescript-server-petstore.sh new file mode 100755 index 00000000000..42df3ecdfa6 --- /dev/null +++ b/bin/typescript-server-petstore.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +SCRIPT="$0" +echo "# START SCRIPT: $SCRIPT" + +while [ -h "$SCRIPT" ] ; do + ls=`ls -ld "$SCRIPT"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=`dirname "$SCRIPT"`/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=`dirname "$SCRIPT"`/.. + APP_DIR=`cd "${APP_DIR}"; pwd` +fi + +executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar" + +if [ ! -f "$executable" ] +then + mvn -B clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g typescript-server -o samples/server/petstore/typescript-server/ $@" + +java $JAVA_OPTS -jar $executable $ags diff --git a/bin/windows/typescript-server-petstore.bat b/bin/windows/typescript-server-petstore.bat new file mode 100644 index 00000000000..8e236044fca --- /dev/null +++ b/bin/windows/typescript-server-petstore.bat @@ -0,0 +1,14 @@ +@ECHO OFF + +set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M + +echo +set ags=generate -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g typescript-server -o samples\server\petstore\typescript-server + +java %JAVA_OPTS% -jar %executable% %ags% diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptServerCodegen.java new file mode 100644 index 00000000000..c8c692caeb2 --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptServerCodegen.java @@ -0,0 +1,201 @@ +/* + * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openapitools.codegen.languages; + +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.parser.util.SchemaTypeUtil; +import org.openapitools.codegen.*; +import org.openapitools.codegen.utils.ModelUtils; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.TreeSet; +import java.util.Date; +import java.util.List; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Map; + +// TODO rename AbstractTypeScriptClientCodegen to AbstractTypeScriptCodegen later +public class TypeScriptServerCodegen extends AbstractTypeScriptClientCodegen { + + public static final String NPM_REPOSITORY = "npmRepository"; + public static final String WITH_INTERFACES = "withInterfaces"; + + protected String npmRepository = null; + + public TypeScriptServerCodegen() { + super(); + + outputFolder = "generated-code/typescript-server"; + embeddedTemplateDir = templateDir = "typescript-server"; + + this.apiPackage = "apis"; + this.apiTemplateFiles.put("apis.mustache", ".ts"); + this.modelPackage = "models"; + this.modelTemplateFiles.put("models.mustache", ".ts"); + + this.cliOptions.add(new CliOption(NPM_REPOSITORY, "Use this property to set an url your private npmRepo in the package.json")); + this.cliOptions.add(new CliOption(WITH_INTERFACES, "Setting this property to true will generate interfaces next to the default class implementations.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); + } + + @Override + public String getName() { + return "typescript-server"; + } + + @Override + public String getHelp() { + return "Generates a TypeScript server stub (beta)."; + } + + public String getNpmRepository() { + return npmRepository; + } + + public void setNpmRepository(String npmRepository) { + this.npmRepository = npmRepository; + } + + @Override + public void processOpts() { + super.processOpts(); + additionalProperties.put("isOriginalModelPropertyNaming", getModelPropertyNaming().equals("original")); + additionalProperties.put("modelPropertyNaming", getModelPropertyNaming()); + supportingFiles.add(new SupportingFile("index.mustache", "", "index.ts")); + supportingFiles.add(new SupportingFile("runtime.mustache", "", "runtime.ts")); + supportingFiles.add(new SupportingFile("apis.index.mustache", apiPackage().replace('.', File.separatorChar), "index.ts")); + supportingFiles.add(new SupportingFile("models.index.mustache", modelPackage().replace('.', File.separatorChar), "index.ts")); + supportingFiles.add(new SupportingFile("tsconfig.mustache", "", "tsconfig.json")); + supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore")); + if (additionalProperties.containsKey(NPM_NAME)) { + addNpmPackageGeneration(); + } + } + + @Override + public boolean isDataTypeFile(final String dataType) { + return dataType != null && dataType.equals("Blob"); + } + + @Override + public String getTypeDeclaration(Schema p) { + Schema inner; + if (ModelUtils.isArraySchema(p)) { + inner = ((ArraySchema) p).getItems(); + return this.getSchemaType(p) + "<" + this.getTypeDeclaration(inner) + ">"; + } else if (ModelUtils.isMapSchema(p)) { + inner = ModelUtils.getAdditionalProperties(p); + return "{ [key: string]: " + this.getTypeDeclaration(inner) + "; }"; + } else if (ModelUtils.isFileSchema(p)) { + return "Blob"; + } else if (ModelUtils.isBinarySchema(p)) { + return "Blob"; + } else if (ModelUtils.isDateSchema(p)) { + return "Date"; + } else if (ModelUtils.isDateTimeSchema(p)) { + return "Date"; + } + return super.getTypeDeclaration(p); + } + + @Override + protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) { + codegenModel.additionalPropertiesType = getTypeDeclaration(ModelUtils.getAdditionalProperties(schema)); + addImport(codegenModel, codegenModel.additionalPropertiesType); + } + + @Override + public Map postProcessModels(Map objs) { + /* comment out the following as we're not sure if we need these in the TS Server generator + // process enum in models + List models = (List) postProcessModelsEnum(objs).get("models"); + for (Object _mo : models) { + Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + cm.imports = new TreeSet(cm.imports); + // name enum with model name, e.g. StatusEnum => PetStatusEnum + for (CodegenProperty var : cm.vars) { + if (Boolean.TRUE.equals(var.isEnum)) { + // behaviour for enum names is specific for typescript to not use namespaces + var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + var.enumName); + } + } + if (cm.parent != null) { + for (CodegenProperty var : cm.allVars) { + if (Boolean.TRUE.equals(var.isEnum)) { + var.datatypeWithEnum = var.datatypeWithEnum + .replace(var.enumName, cm.classname + var.enumName); + } + } + } + } + */ + + return objs; + } + + @Override + public Map postProcessAllModels(Map objs) { + Map result = super.postProcessAllModels(objs); + + /* comment out the following as we're not sure if we need these in the TS Server generator + for (Map.Entry entry : result.entrySet()) { + Map inner = (Map) entry.getValue(); + List> models = (List>) inner.get("models"); + for (Map model : models) { + CodegenModel codegenModel = (CodegenModel) model.get("model"); + model.put("hasImports", codegenModel.imports.size() > 0); + } + } + */ + return result; + } + + @Override + public String getSchemaType(Schema p) { + String openAPIType = super.getSchemaType(p); + if (isLanguagePrimitive(openAPIType)) { + return openAPIType; + } + applyLocalTypeMapping(openAPIType); + return openAPIType; + } + + private String applyLocalTypeMapping(String type) { + if (typeMapping.containsKey(type)) { + type = typeMapping.get(type); + } + return type; + } + + private boolean isLanguagePrimitive(String type) { + return languageSpecificPrimitives.contains(type); + } + + private void addNpmPackageGeneration() { + if (additionalProperties.containsKey(NPM_REPOSITORY)) { + this.setNpmRepository(additionalProperties.get(NPM_REPOSITORY).toString()); + } + + // Files for building our lib + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); + } + +} diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index 87020fffa16..f35ce06b419 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -127,3 +127,4 @@ org.openapitools.codegen.languages.TypeScriptJqueryClientCodegen org.openapitools.codegen.languages.TypeScriptNodeClientCodegen org.openapitools.codegen.languages.TypeScriptReduxQueryClientCodegen org.openapitools.codegen.languages.TypeScriptRxjsClientCodegen +org.openapitools.codegen.languages.TypeScriptServerCodegen diff --git a/modules/openapi-generator/src/main/resources/typescript-server/README.mustache b/modules/openapi-generator/src/main/resources/typescript-server/README.mustache new file mode 100644 index 00000000000..017994bbe86 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/README.mustache @@ -0,0 +1,87 @@ +## {{npmName}}@{{npmVersion}} + +This generator creates TypeScript/JavaScript client that utilizes [RxJS](https://rxjs-dev.firebaseapp.com/). The generated Node module can be used in the following environments: + +Environment +* Node.js +* Webpack +* Browserify + +Language level +* ES5 - you must have a Promises/A+ library installed +* ES6 + +Module system +* CommonJS +* ES6 module system + +It can be used in both TypeScript and JavaScript. In TypeScript, the definition should be automatically resolved via `package.json`. ([Reference](http://www.typescriptlang.org/docs/handbook/typings-for-npm-packages.html)) + +### Building + +To build and compile the typescript sources to javascript use: +``` +npm install +npm run build +``` + +### Publishing + +First build the package then run `npm publish` + +### Consuming + +navigate to the folder of your consuming project and run one of the following commands. + +_published:_ + +``` +npm install {{npmName}}@{{npmVersion}} --save +``` + +_unPublished (not recommended):_ + +``` +npm install PATH_TO_GENERATED_PACKAGE --save +``` + +### How to apply middleware + +First, add a singleton class that extends the generated `Configuration` class. + +``` +export class AuthInterceptor extends Configuration { + private static config: AuthInterceptor; + + private constructor() { + const middleware: Middleware[] = [ + { + pre(request: RequestArgs): RequestArgs { + const token = getAuthToken(); + + return { + ...request, + headers: { + ...request.headers, + Authorization: `Bearer ${token}`, + }, + }; + }, + }, + ]; + + super({ middleware }); + } + + public static get Instance() { + return AuthInterceptor.config || (AuthInterceptor.config = new this()); + } +} +``` + +Next, pass it to the generated api controller. + +``` +const api = new StoreApi(AuthInterceptor.Instance); + +``` diff --git a/modules/openapi-generator/src/main/resources/typescript-server/apis.index.mustache b/modules/openapi-generator/src/main/resources/typescript-server/apis.index.mustache new file mode 100644 index 00000000000..6286332d7bc --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/apis.index.mustache @@ -0,0 +1,7 @@ +{{#apiInfo}} +{{#apis}} +{{#operations}} +export * from './{{ classFilename }}'; +{{/operations}} +{{/apis}} +{{/apiInfo}} diff --git a/modules/openapi-generator/src/main/resources/typescript-server/apis.mustache b/modules/openapi-generator/src/main/resources/typescript-server/apis.mustache new file mode 100644 index 00000000000..3c548d7b547 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/apis.mustache @@ -0,0 +1,204 @@ +// tslint:disable +{{>licenseInfo}} +import { Observable } from 'rxjs'; +import { BaseAPI{{#hasHttpHeaders}}, HttpHeaders{{/hasHttpHeaders}}{{#hasQueryParams}}, HttpQuery{{/hasQueryParams}}{{#hasRequiredParameters}}, throwIfRequired{{/hasRequiredParameters}}{{#hasPathParams}}, encodeURI{{/hasPathParams}}{{#hasListContainers}}, COLLECTION_FORMATS{{/hasListContainers}} } from '../runtime'; +{{#imports.0}} +import { + {{#imports}} + {{className}}, + {{/imports}} +} from '../models'; +{{/imports.0}} + +{{#operations}} +{{#operation}} +{{#allParams.0}} +export interface {{operationIdCamelCase}}Request { + {{#allParams}} + {{paramName}}{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}; + {{/allParams}} +} + +{{/allParams.0}} +{{/operation}} +{{/operations}} +{{#operations}} +/** + * {{#description}}{{{description}}}{{/description}}{{^description}}no description{{/description}} + */ +export class {{classname}} extends BaseAPI { + + {{#operation}} + /** + {{#notes}} + * {{¬es}} + {{/notes}} + {{#summary}} + * {{&summary}} + {{/summary}} + */ + {{nickname}} = ({{#allParams.0}}requestParameters: {{operationIdCamelCase}}Request{{/allParams.0}}): Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}> => { + {{#hasParams}} + {{#allParams}} + {{#required}} + throwIfRequired(requestParameters, '{{paramName}}', '{{nickname}}'); + {{/required}} + {{/allParams}} + + {{/hasParams}} + {{#hasHttpHeaders}} + const headers: HttpHeaders = { + {{#bodyParam}} + {{^consumes}} + 'Content-Type': 'application/json', + {{/consumes}} + {{#consumes.0}} + 'Content-Type': '{{{mediaType}}}', + {{/consumes.0}} + {{/bodyParam}} + {{#headerParams}} + {{#isListContainer}} + ...(requestParameters.{{paramName}} && { '{{baseName}}': requestParameters.{{paramName}}.join(COLLECTION_FORMATS['{{collectionFormat}}'])) }), + {{/isListContainer}} + {{^isListContainer}} + ...(requestParameters.{{paramName}} && { '{{baseName}}': String(requestParameters.{{paramName}}) }), + {{/isListContainer}} + {{/headerParams}} + {{#authMethods}} + {{#isBasic}} + ...(this.configuration.username && this.configuration.password && { Authorization: `Basic ${btoa(this.configuration.username + ':' + this.configuration.password)}` }), + {{/isBasic}} + {{#isApiKey}} + {{#isKeyInHeader}} + ...(this.configuration.apiKey && { '{{keyParamName}}': this.configuration.apiKey('{{keyParamName}}') }), // {{name}} authentication + {{/isKeyInHeader}} + {{/isApiKey}} + {{#isOAuth}} + // oauth required + ...(this.configuration.accessToken && { + Authorization: this.configuration.accessToken && (typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken('{{name}}', [{{#scopes}}'{{{scope}}}'{{^-last}}, {{/-last}}{{/scopes}}]) + : this.configuration.accessToken) + }), + {{/isOAuth}} + {{/authMethods}} + }; + + {{/hasHttpHeaders}} + {{#hasQueryParams}} + const query: HttpQuery = { + {{#queryParams}} + {{#isListContainer}} + {{#isCollectionFormatMulti}} + ...(requestParameters.{{paramName}} && { '{{baseName}}': requestParameters.{{paramName}} }), + {{/isCollectionFormatMulti}} + {{^isCollectionFormatMulti}} + ...(requestParameters.{{paramName}} && { '{{baseName}}': requestParameters.{{paramName}}.join(COLLECTION_FORMATS['{{collectionFormat}}']) }), + {{/isCollectionFormatMulti}} + {{/isListContainer}} + {{^isListContainer}} + {{#isDateTime}} + ...(requestParameters.{{paramName}} && { '{{baseName}}': (requestParameters.{{paramName}} as any).toISOString() }), + {{/isDateTime}} + {{^isDateTime}} + {{#isDate}} + ...(requestParameters.{{paramName}} && { '{{baseName}}': (requestParameters.{{paramName}} as any).toISOString() }), + {{/isDate}} + {{^isDate}} + ...(requestParameters.{{paramName}} && { '{{baseName}}': requestParameters.{{paramName}} }), + {{/isDate}} + {{/isDateTime}} + {{/isListContainer}} + {{/queryParams}} + {{#authMethods}} + {{#isApiKey}} + {{#isKeyInQuery}} + ...(this.configuration.apiKey && { '{{keyParamName}}': this.configuration.apiKey && this.configuration.apiKey('{{keyParamName}}') }), // {{name}} authentication + {{/isKeyInQuery}} + {{/isApiKey}} + {{/authMethods}} + }; + + {{/hasQueryParams}} + {{#hasFormParams}} + const formData = new FormData(); + {{/hasFormParams}} + {{#formParams}} + {{#isListContainer}} + if (requestParameters.{{paramName}}) { + {{#isCollectionFormatMulti}} + requestParameters.{{paramName}}.forEach((element) => { + formData.append('{{baseName}}', element as any); + }) + {{/isCollectionFormatMulti}} + {{^isCollectionFormatMulti}} + formData.append('{{baseName}}', requestParameters.{{paramName}}.join(COLLECTION_FORMATS['{{collectionFormat}}'])); + {{/isCollectionFormatMulti}} + } + + {{/isListContainer}} + {{^isListContainer}} + if (requestParameters.{{paramName}} !== undefined) { + formData.append('{{baseName}}', requestParameters.{{paramName}} as any); + } + + {{/isListContainer}} + {{/formParams}} + return this.request<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}>({ + path: '{{{path}}}'{{#pathParams}}.replace({{=<% %>=}}'{<%baseName%>}'<%={{ }}=%>, encodeURI(requestParameters.{{paramName}})){{/pathParams}}, + method: '{{httpMethod}}', + {{#hasHttpHeaders}} + headers, + {{/hasHttpHeaders}} + {{#hasQueryParams}} + query, + {{/hasQueryParams}} + {{#hasBodyParam}} + {{#bodyParam}} + {{#isContainer}} + body: requestParameters.{{paramName}}, + {{/isContainer}} + {{^isContainer}} + {{^isPrimitiveType}} + body: requestParameters.{{paramName}}, + {{/isPrimitiveType}} + {{#isPrimitiveType}} + body: requestParameters.{{paramName}} as any, + {{/isPrimitiveType}} + {{/isContainer}} + {{/bodyParam}} + {{/hasBodyParam}} + {{#hasFormParams}} + body: formData, + {{/hasFormParams}} +{{#isResponseFile}} + responseType: 'blob' +{{/isResponseFile}} + }); + }; + + {{/operation}} +} +{{/operations}} +{{#hasEnums}} + +{{#operations}} +{{#operation}} +{{#allParams}} +{{#isEnum}} +/** + * @export + * @enum {string} + */ +export enum {{operationIdCamelCase}}{{enumName}} { +{{#allowableValues}} + {{#enumVars}} + {{{name}}} = {{{value}}}{{^-last}},{{/-last}} + {{/enumVars}} +{{/allowableValues}} +} +{{/isEnum}} +{{/allParams}} +{{/operation}} +{{/operations}} +{{/hasEnums}} diff --git a/modules/openapi-generator/src/main/resources/typescript-server/gitignore b/modules/openapi-generator/src/main/resources/typescript-server/gitignore new file mode 100644 index 00000000000..149b5765472 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/gitignore @@ -0,0 +1,4 @@ +wwwroot/*.js +node_modules +typings +dist diff --git a/modules/openapi-generator/src/main/resources/typescript-server/index.mustache b/modules/openapi-generator/src/main/resources/typescript-server/index.mustache new file mode 100644 index 00000000000..848ecfa4d10 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/index.mustache @@ -0,0 +1,3 @@ +export * from './runtime'; +export * from './apis'; +export * from './models'; diff --git a/modules/openapi-generator/src/main/resources/typescript-server/licenseInfo.mustache b/modules/openapi-generator/src/main/resources/typescript-server/licenseInfo.mustache new file mode 100644 index 00000000000..9866f297a4d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/licenseInfo.mustache @@ -0,0 +1,11 @@ +/** + * {{{appName}}} + * {{{appDescription}}} + * + * {{#version}}The version of the OpenAPI document: {{{version}}}{{/version}} + * {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ diff --git a/modules/openapi-generator/src/main/resources/typescript-server/modelEnum.mustache b/modules/openapi-generator/src/main/resources/typescript-server/modelEnum.mustache new file mode 100644 index 00000000000..dc04cb0bd63 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/modelEnum.mustache @@ -0,0 +1,12 @@ +/** + * {{{description}}} + * @export + * @enum {string} + */ +export enum {{classname}} { +{{#allowableValues}} +{{#enumVars}} + {{{name}}} = {{{value}}}{{^-last}},{{/-last}} +{{/enumVars}} +{{/allowableValues}} +} diff --git a/modules/openapi-generator/src/main/resources/typescript-server/modelGeneric.mustache b/modules/openapi-generator/src/main/resources/typescript-server/modelGeneric.mustache new file mode 100644 index 00000000000..543ab776e4d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/modelGeneric.mustache @@ -0,0 +1,43 @@ +{{#hasImports}} +import { + {{#imports}} + {{{.}}}, + {{/imports}} +} from './'; + +{{/hasImports}} +/**{{#description}} + * {{{description}}}{{/description}} + * @export + * @interface {{classname}} + */ +export interface {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{ +{{#additionalPropertiesType}} + [key: string]: {{{additionalPropertiesType}}}{{#hasVars}} | any{{/hasVars}}; +{{/additionalPropertiesType}} +{{#vars}} + /**{{#description}} + * {{{description}}}{{/description}} + * @type {{=<% %>=}}{<%&datatype%>}<%={{ }}=%> + * @memberof {{classname}} + */ + {{#isReadOnly}}readonly {{/isReadOnly}}{{name}}{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}}; +{{/vars}} +}{{#hasEnums}} + +{{#vars}} +{{#isEnum}} +/** + * @export + * @enum {string} + */ +export enum {{classname}}{{enumName}} { +{{#allowableValues}} + {{#enumVars}} + {{{name}}} = {{{value}}}{{^-last}},{{/-last}} + {{/enumVars}} +{{/allowableValues}} +} +{{/isEnum}} +{{/vars}} +{{/hasEnums}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/typescript-server/modelOneOf.mustache b/modules/openapi-generator/src/main/resources/typescript-server/modelOneOf.mustache new file mode 100644 index 00000000000..11e4f25fba4 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/modelOneOf.mustache @@ -0,0 +1,14 @@ +{{#hasImports}} +import { + {{#imports}} + {{{.}}}, + {{/imports}} +} from './'; + +{{/hasImports}} +/** + * @type {{classname}}{{#description}} + * {{{description}}}{{/description}} + * @export + */ +export type {{classname}} = {{#oneOf}}{{{.}}}{{^-last}} | {{/-last}}{{/oneOf}}; \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/typescript-server/models.index.mustache b/modules/openapi-generator/src/main/resources/typescript-server/models.index.mustache new file mode 100644 index 00000000000..02a39c248c4 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/models.index.mustache @@ -0,0 +1,5 @@ +{{#models}} +{{#model}} +export * from './{{{ classFilename }}}'; +{{/model}} +{{/models}} diff --git a/modules/openapi-generator/src/main/resources/typescript-server/models.mustache b/modules/openapi-generator/src/main/resources/typescript-server/models.mustache new file mode 100644 index 00000000000..ae5738af984 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/models.mustache @@ -0,0 +1,7 @@ +// tslint:disable +{{>licenseInfo}} +{{#models}} +{{#model}} +{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{#oneOf}}{{#-first}}{{>modelOneOf}}{{/-first}}{{/oneOf}}{{^isEnum}}{{^oneOf}}{{>modelGeneric}}{{/oneOf}}{{/isEnum}} +{{/model}} +{{/models}} diff --git a/modules/openapi-generator/src/main/resources/typescript-server/package.mustache b/modules/openapi-generator/src/main/resources/typescript-server/package.mustache new file mode 100644 index 00000000000..89f0f03561c --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/package.mustache @@ -0,0 +1,23 @@ +{ + "name": "{{npmName}}", + "version": "{{npmVersion}}", + "description": "OpenAPI client for {{npmName}}", + "author": "OpenAPI-Generator", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "scripts" : { + "build": "tsc --outDir dist/", + "prepare": "npm run build" + }, + "dependencies": { + "rxjs": "^6.3.3" + }, + "devDependencies": { + "typescript": "^3.0.1" + }{{#npmRepository}},{{/npmRepository}} +{{#npmRepository}} + "publishConfig": { + "registry": "{{npmRepository}}" + } +{{/npmRepository}} +} diff --git a/modules/openapi-generator/src/main/resources/typescript-server/runtime.mustache b/modules/openapi-generator/src/main/resources/typescript-server/runtime.mustache new file mode 100644 index 00000000000..7c58be70a52 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/runtime.mustache @@ -0,0 +1,183 @@ +// tslint:disable +{{>licenseInfo}} +import { Observable, of } from 'rxjs'; +import { ajax, AjaxRequest, AjaxResponse } from 'rxjs/ajax'; +import { map, concatMap } from 'rxjs/operators'; + +export const BASE_PATH = '{{{basePath}}}'.replace(/\/+$/, ''); + +export interface ConfigurationParameters { + basePath?: string; // override base path + middleware?: Middleware[]; // middleware to apply before/after rxjs requests + username?: string; // parameter for basic security + password?: string; // parameter for basic security + apiKey?: string | ((name: string) => string); // parameter for apiKey security + accessToken?: string | ((name?: string, scopes?: string[]) => string); // parameter for oauth2 security +} + +export class Configuration { + constructor(private configuration: ConfigurationParameters = {}) {} + + get basePath(): string { + return this.configuration.basePath || BASE_PATH; + } + + get middleware(): Middleware[] { + return this.configuration.middleware || []; + } + + get username(): string | undefined { + return this.configuration.username; + } + + get password(): string | undefined { + return this.configuration.password; + } + + get apiKey(): ((name: string) => string) | undefined { + const apiKey = this.configuration.apiKey; + if (apiKey) { + return typeof apiKey === 'function' ? apiKey : () => apiKey; + } + return undefined; + } + + get accessToken(): ((name: string, scopes?: string[]) => string) | undefined { + const accessToken = this.configuration.accessToken; + if (accessToken) { + return typeof accessToken === 'function' ? accessToken : () => accessToken; + } + return undefined; + } +} + +/** + * This is the base class for all generated API classes. + */ +export class BaseAPI { + private middleware: Middleware[] = []; + + constructor(protected configuration = new Configuration()) { + this.middleware = configuration.middleware; + } + + withMiddleware = (middlewares: Middleware[]) => { + const next = this.clone(); + next.middleware = next.middleware.concat(middlewares); + return next; + }; + + withPreMiddleware = (preMiddlewares: Array) => + this.withMiddleware(preMiddlewares.map((pre) => ({ pre }))); + + withPostMiddleware = (postMiddlewares: Array) => + this.withMiddleware(postMiddlewares.map((post) => ({ post }))); + + protected request = (requestOpts: RequestOpts): Observable => + this.rxjsRequest(this.createRequestArgs(requestOpts)).pipe( + map((res) => { + if (res.status >= 200 && res.status < 300) { + return res.response as T; + } + throw res; + }) + ); + + private createRequestArgs = (requestOpts: RequestOpts): RequestArgs => { + let url = this.configuration.basePath + requestOpts.path; + if (requestOpts.query !== undefined && Object.keys(requestOpts.query).length !== 0) { + // only add the queryString to the URL if there are query parameters. + // this is done to avoid urls ending with a '?' character which buggy webservers + // do not handle correctly sometimes. + url += '?' + queryString(requestOpts.query); + } + + return { + url, + method: requestOpts.method, + headers: requestOpts.headers, + body: requestOpts.body instanceof FormData ? requestOpts.body : JSON.stringify(requestOpts.body), + responseType: requestOpts.responseType || 'json', + }; + } + + private rxjsRequest = (params: RequestArgs): Observable => + of(params).pipe( + map((request) => { + this.middleware.filter((item) => item.pre).forEach((mw) => (request = mw.pre!(request))); + return request; + }), + concatMap((args) => + ajax(args).pipe( + map((response) => { + this.middleware.filter((item) => item.post).forEach((mw) => (response = mw.post!(response))); + return response; + }) + ) + ) + ); + + /** + * Create a shallow clone of `this` by constructing a new instance + * and then shallow cloning data members. + */ + private clone = (): T => + Object.assign(Object.create(Object.getPrototypeOf(this)), this); +} + +// export for not being a breaking change +export class RequiredError extends Error { + name: 'RequiredError' = 'RequiredError'; +} + +export const COLLECTION_FORMATS = { + csv: ',', + ssv: ' ', + tsv: '\t', + pipes: '|', +}; + +export type Json = any; +export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; +export type HttpHeaders = { [key: string]: string }; +export type HttpQuery = Partial<{ [key: string]: string | number | null | boolean | Array }>; // partial is needed for strict mode +export type HttpBody = Json | FormData; +export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; + +export interface RequestOpts { + path: string; + method: HttpMethod; + headers?: HttpHeaders; + query?: HttpQuery; + body?: HttpBody; + responseType?: 'json' | 'blob' | 'arraybuffer' | 'text'; +} + +export const encodeURI = (value: any) => encodeURIComponent(String(value)); + +const queryString = (params: HttpQuery): string => Object.keys(params) + .map((key) => { + const value = params[key]; + return (value instanceof Array) + ? value.map((val) => `${encodeURI(key)}=${encodeURI(val)}`).join('&') + : `${encodeURI(key)}=${encodeURI(value)}`; + }) + .join('&'); + +// alias fallback for not being a breaking change +export const querystring = queryString; + +export const throwIfRequired = (params: {[key: string]: any}, key: string, nickname: string) => { + if (!params || params[key] === null || params[key] === undefined) { + throw new RequiredError(`Required parameter ${key} was null or undefined when calling ${nickname}.`); + } +}; + +// alias for easier importing +export interface RequestArgs extends AjaxRequest {} +export interface ResponseArgs extends AjaxResponse {} + +export interface Middleware { + pre?(request: RequestArgs): RequestArgs; + post?(response: ResponseArgs): ResponseArgs; +} diff --git a/modules/openapi-generator/src/main/resources/typescript-server/tsconfig.mustache b/modules/openapi-generator/src/main/resources/typescript-server/tsconfig.mustache new file mode 100644 index 00000000000..328c7d4e141 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-server/tsconfig.mustache @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "declaration": true, + "target": "{{#supportsES6}}es6{{/supportsES6}}{{^supportsES6}}es5{{/supportsES6}}", + "module": "commonjs", + "moduleResolution": "node", + "outDir": "dist", + "rootDir": ".", + {{^supportsES6}} + "lib": [ + "es6", + "dom" + ], + {{/supportsES6}} + "typeRoots": [ + "node_modules/@types" + ] + }, + "exclude": [ + "dist", + "node_modules" + ] +} diff --git a/samples/server/petstore/typescript-server/.gitignore b/samples/server/petstore/typescript-server/.gitignore new file mode 100644 index 00000000000..149b5765472 --- /dev/null +++ b/samples/server/petstore/typescript-server/.gitignore @@ -0,0 +1,4 @@ +wwwroot/*.js +node_modules +typings +dist diff --git a/samples/server/petstore/typescript-server/.openapi-generator-ignore b/samples/server/petstore/typescript-server/.openapi-generator-ignore new file mode 100644 index 00000000000..7484ee590a3 --- /dev/null +++ b/samples/server/petstore/typescript-server/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/typescript-server/.openapi-generator/VERSION b/samples/server/petstore/typescript-server/.openapi-generator/VERSION new file mode 100644 index 00000000000..d168f1d8bda --- /dev/null +++ b/samples/server/petstore/typescript-server/.openapi-generator/VERSION @@ -0,0 +1 @@ +4.2.1-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/typescript-server/apis/PetApi.ts b/samples/server/petstore/typescript-server/apis/PetApi.ts new file mode 100644 index 00000000000..942943f8b4a --- /dev/null +++ b/samples/server/petstore/typescript-server/apis/PetApi.ts @@ -0,0 +1,194 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { Observable } from 'rxjs'; +import { BaseAPI } from '../runtime'; +import { + , + , +} from '../models'; + +export interface AddPetRequest { + body: Pet; +} + +export interface DeletePetRequest { + petId: number; + apiKey?: string; +} + +export interface FindPetsByStatusRequest { + status: Array; +} + +export interface FindPetsByTagsRequest { + tags: Array; +} + +export interface GetPetByIdRequest { + petId: number; +} + +export interface UpdatePetRequest { + body: Pet; +} + +export interface UpdatePetWithFormRequest { + petId: number; + name?: string; + status?: string; +} + +export interface UploadFileRequest { + petId: number; + additionalMetadata?: string; + file?: Blob; +} + +/** + * no description + */ +export class PetApi extends BaseAPI { + + /** + * Add a new pet to the store + */ + addPet = (requestParameters: AddPetRequest): Observable => { + throwIfRequired(requestParameters, 'body', 'addPet'); + + return this.request({ + path: '/pet', + method: 'POST', + body: requestParameters.body, + }); + }; + + /** + * Deletes a pet + */ + deletePet = (requestParameters: DeletePetRequest): Observable => { + throwIfRequired(requestParameters, 'petId', 'deletePet'); + + return this.request({ + path: '/pet/{petId}'.replace('{petId}', encodeURI(requestParameters.petId)), + method: 'DELETE', + }); + }; + + /** + * Multiple status values can be provided with comma separated strings + * Finds Pets by status + */ + findPetsByStatus = (requestParameters: FindPetsByStatusRequest): Observable> => { + throwIfRequired(requestParameters, 'status', 'findPetsByStatus'); + + const query: HttpQuery = { + ...(requestParameters.status && { 'status': requestParameters.status.join(COLLECTION_FORMATS['csv']) }), + }; + + return this.request>({ + path: '/pet/findByStatus', + method: 'GET', + query, + }); + }; + + /** + * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. + * Finds Pets by tags + */ + findPetsByTags = (requestParameters: FindPetsByTagsRequest): Observable> => { + throwIfRequired(requestParameters, 'tags', 'findPetsByTags'); + + const query: HttpQuery = { + ...(requestParameters.tags && { 'tags': requestParameters.tags.join(COLLECTION_FORMATS['csv']) }), + }; + + return this.request>({ + path: '/pet/findByTags', + method: 'GET', + query, + }); + }; + + /** + * Returns a single pet + * Find pet by ID + */ + getPetById = (requestParameters: GetPetByIdRequest): Observable => { + throwIfRequired(requestParameters, 'petId', 'getPetById'); + + return this.request({ + path: '/pet/{petId}'.replace('{petId}', encodeURI(requestParameters.petId)), + method: 'GET', + }); + }; + + /** + * Update an existing pet + */ + updatePet = (requestParameters: UpdatePetRequest): Observable => { + throwIfRequired(requestParameters, 'body', 'updatePet'); + + return this.request({ + path: '/pet', + method: 'PUT', + body: requestParameters.body, + }); + }; + + /** + * Updates a pet in the store with form data + */ + updatePetWithForm = (requestParameters: UpdatePetWithFormRequest): Observable => { + throwIfRequired(requestParameters, 'petId', 'updatePetWithForm'); + + const formData = new FormData(); + if (requestParameters.name !== undefined) { + formData.append('name', requestParameters.name as any); + } + + if (requestParameters.status !== undefined) { + formData.append('status', requestParameters.status as any); + } + + return this.request({ + path: '/pet/{petId}'.replace('{petId}', encodeURI(requestParameters.petId)), + method: 'POST', + body: formData, + }); + }; + + /** + * uploads an image + */ + uploadFile = (requestParameters: UploadFileRequest): Observable => { + throwIfRequired(requestParameters, 'petId', 'uploadFile'); + + const formData = new FormData(); + if (requestParameters.additionalMetadata !== undefined) { + formData.append('additionalMetadata', requestParameters.additionalMetadata as any); + } + + if (requestParameters.file !== undefined) { + formData.append('file', requestParameters.file as any); + } + + return this.request({ + path: '/pet/{petId}/uploadImage'.replace('{petId}', encodeURI(requestParameters.petId)), + method: 'POST', + body: formData, + }); + }; + +} diff --git a/samples/server/petstore/typescript-server/apis/StoreApi.ts b/samples/server/petstore/typescript-server/apis/StoreApi.ts new file mode 100644 index 00000000000..ddd2787f943 --- /dev/null +++ b/samples/server/petstore/typescript-server/apis/StoreApi.ts @@ -0,0 +1,87 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { Observable } from 'rxjs'; +import { BaseAPI } from '../runtime'; +import { + , +} from '../models'; + +export interface DeleteOrderRequest { + orderId: string; +} + +export interface GetOrderByIdRequest { + orderId: number; +} + +export interface PlaceOrderRequest { + body: Order; +} + +/** + * no description + */ +export class StoreApi extends BaseAPI { + + /** + * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + * Delete purchase order by ID + */ + deleteOrder = (requestParameters: DeleteOrderRequest): Observable => { + throwIfRequired(requestParameters, 'orderId', 'deleteOrder'); + + return this.request({ + path: '/store/order/{orderId}'.replace('{orderId}', encodeURI(requestParameters.orderId)), + method: 'DELETE', + }); + }; + + /** + * Returns a map of status codes to quantities + * Returns pet inventories by status + */ + getInventory = (): Observable<{ [key: string]: number; }> => { + return this.request<{ [key: string]: number; }>({ + path: '/store/inventory', + method: 'GET', + }); + }; + + /** + * For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions + * Find purchase order by ID + */ + getOrderById = (requestParameters: GetOrderByIdRequest): Observable => { + throwIfRequired(requestParameters, 'orderId', 'getOrderById'); + + return this.request({ + path: '/store/order/{orderId}'.replace('{orderId}', encodeURI(requestParameters.orderId)), + method: 'GET', + }); + }; + + /** + * Place an order for a pet + */ + placeOrder = (requestParameters: PlaceOrderRequest): Observable => { + throwIfRequired(requestParameters, 'body', 'placeOrder'); + + return this.request({ + path: '/store/order', + method: 'POST', + body: requestParameters.body, + }); + }; + +} diff --git a/samples/server/petstore/typescript-server/apis/UserApi.ts b/samples/server/petstore/typescript-server/apis/UserApi.ts new file mode 100644 index 00000000000..26d493a9b9c --- /dev/null +++ b/samples/server/petstore/typescript-server/apis/UserApi.ts @@ -0,0 +1,164 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { Observable } from 'rxjs'; +import { BaseAPI } from '../runtime'; +import { + , +} from '../models'; + +export interface CreateUserRequest { + body: User; +} + +export interface CreateUsersWithArrayInputRequest { + body: Array; +} + +export interface CreateUsersWithListInputRequest { + body: Array; +} + +export interface DeleteUserRequest { + username: string; +} + +export interface GetUserByNameRequest { + username: string; +} + +export interface LoginUserRequest { + username: string; + password: string; +} + +export interface UpdateUserRequest { + username: string; + body: User; +} + +/** + * no description + */ +export class UserApi extends BaseAPI { + + /** + * This can only be done by the logged in user. + * Create user + */ + createUser = (requestParameters: CreateUserRequest): Observable => { + throwIfRequired(requestParameters, 'body', 'createUser'); + + return this.request({ + path: '/user', + method: 'POST', + body: requestParameters.body, + }); + }; + + /** + * Creates list of users with given input array + */ + createUsersWithArrayInput = (requestParameters: CreateUsersWithArrayInputRequest): Observable => { + throwIfRequired(requestParameters, 'body', 'createUsersWithArrayInput'); + + return this.request({ + path: '/user/createWithArray', + method: 'POST', + body: requestParameters.body, + }); + }; + + /** + * Creates list of users with given input array + */ + createUsersWithListInput = (requestParameters: CreateUsersWithListInputRequest): Observable => { + throwIfRequired(requestParameters, 'body', 'createUsersWithListInput'); + + return this.request({ + path: '/user/createWithList', + method: 'POST', + body: requestParameters.body, + }); + }; + + /** + * This can only be done by the logged in user. + * Delete user + */ + deleteUser = (requestParameters: DeleteUserRequest): Observable => { + throwIfRequired(requestParameters, 'username', 'deleteUser'); + + return this.request({ + path: '/user/{username}'.replace('{username}', encodeURI(requestParameters.username)), + method: 'DELETE', + }); + }; + + /** + * Get user by user name + */ + getUserByName = (requestParameters: GetUserByNameRequest): Observable => { + throwIfRequired(requestParameters, 'username', 'getUserByName'); + + return this.request({ + path: '/user/{username}'.replace('{username}', encodeURI(requestParameters.username)), + method: 'GET', + }); + }; + + /** + * Logs user into the system + */ + loginUser = (requestParameters: LoginUserRequest): Observable => { + throwIfRequired(requestParameters, 'username', 'loginUser'); + throwIfRequired(requestParameters, 'password', 'loginUser'); + + const query: HttpQuery = { + ...(requestParameters.username && { 'username': requestParameters.username }), + ...(requestParameters.password && { 'password': requestParameters.password }), + }; + + return this.request({ + path: '/user/login', + method: 'GET', + query, + }); + }; + + /** + * Logs out current logged in user session + */ + logoutUser = (): Observable => { + return this.request({ + path: '/user/logout', + method: 'GET', + }); + }; + + /** + * This can only be done by the logged in user. + * Updated user + */ + updateUser = (requestParameters: UpdateUserRequest): Observable => { + throwIfRequired(requestParameters, 'username', 'updateUser'); + throwIfRequired(requestParameters, 'body', 'updateUser'); + + return this.request({ + path: '/user/{username}'.replace('{username}', encodeURI(requestParameters.username)), + method: 'PUT', + body: requestParameters.body, + }); + }; + +} diff --git a/samples/server/petstore/typescript-server/apis/index.ts b/samples/server/petstore/typescript-server/apis/index.ts new file mode 100644 index 00000000000..056206bfaca --- /dev/null +++ b/samples/server/petstore/typescript-server/apis/index.ts @@ -0,0 +1,3 @@ +export * from './PetApi'; +export * from './StoreApi'; +export * from './UserApi'; diff --git a/samples/server/petstore/typescript-server/index.ts b/samples/server/petstore/typescript-server/index.ts new file mode 100644 index 00000000000..848ecfa4d10 --- /dev/null +++ b/samples/server/petstore/typescript-server/index.ts @@ -0,0 +1,3 @@ +export * from './runtime'; +export * from './apis'; +export * from './models'; diff --git a/samples/server/petstore/typescript-server/models/ApiResponse.ts b/samples/server/petstore/typescript-server/models/ApiResponse.ts new file mode 100644 index 00000000000..942e4b992bf --- /dev/null +++ b/samples/server/petstore/typescript-server/models/ApiResponse.ts @@ -0,0 +1,35 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * Describes the result of uploading an image resource + * @export + * @interface ApiResponse + */ +export interface ApiResponse { + /** + * @type {number} + * @memberof ApiResponse + */ + code?: number; + /** + * @type {string} + * @memberof ApiResponse + */ + type?: string; + /** + * @type {string} + * @memberof ApiResponse + */ + message?: string; +} diff --git a/samples/server/petstore/typescript-server/models/Category.ts b/samples/server/petstore/typescript-server/models/Category.ts new file mode 100644 index 00000000000..4e1d3e51e2e --- /dev/null +++ b/samples/server/petstore/typescript-server/models/Category.ts @@ -0,0 +1,30 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * A category for a pet + * @export + * @interface Category + */ +export interface Category { + /** + * @type {number} + * @memberof Category + */ + id?: number; + /** + * @type {string} + * @memberof Category + */ + name?: string; +} diff --git a/samples/server/petstore/typescript-server/models/Order.ts b/samples/server/petstore/typescript-server/models/Order.ts new file mode 100644 index 00000000000..394f8f4dfc3 --- /dev/null +++ b/samples/server/petstore/typescript-server/models/Order.ts @@ -0,0 +1,59 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * An order for a pets from the pet store + * @export + * @interface Order + */ +export interface Order { + /** + * @type {number} + * @memberof Order + */ + id?: number; + /** + * @type {number} + * @memberof Order + */ + petId?: number; + /** + * @type {number} + * @memberof Order + */ + quantity?: number; + /** + * @type {Date} + * @memberof Order + */ + shipDate?: Date; + /** + * Order Status + * @type {string} + * @memberof Order + */ + status?: StatusEnum; + /** + * @type {boolean} + * @memberof Order + */ + complete?: boolean; +} + +/** + * @export + * @enum {string} + */ +export enum OrderStatusEnum { +} + diff --git a/samples/server/petstore/typescript-server/models/Pet.ts b/samples/server/petstore/typescript-server/models/Pet.ts new file mode 100644 index 00000000000..e835049368e --- /dev/null +++ b/samples/server/petstore/typescript-server/models/Pet.ts @@ -0,0 +1,59 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * A pet for sale in the pet store + * @export + * @interface Pet + */ +export interface Pet { + /** + * @type {number} + * @memberof Pet + */ + id?: number; + /** + * @type {Category} + * @memberof Pet + */ + category?: Category; + /** + * @type {string} + * @memberof Pet + */ + name: string; + /** + * @type {Array} + * @memberof Pet + */ + photoUrls: Array; + /** + * @type {Array} + * @memberof Pet + */ + tags?: Array; + /** + * pet status in the store + * @type {string} + * @memberof Pet + */ + status?: StatusEnum; +} + +/** + * @export + * @enum {string} + */ +export enum PetStatusEnum { +} + diff --git a/samples/server/petstore/typescript-server/models/Tag.ts b/samples/server/petstore/typescript-server/models/Tag.ts new file mode 100644 index 00000000000..58792b18e6b --- /dev/null +++ b/samples/server/petstore/typescript-server/models/Tag.ts @@ -0,0 +1,30 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * A tag for a pet + * @export + * @interface Tag + */ +export interface Tag { + /** + * @type {number} + * @memberof Tag + */ + id?: number; + /** + * @type {string} + * @memberof Tag + */ + name?: string; +} diff --git a/samples/server/petstore/typescript-server/models/User.ts b/samples/server/petstore/typescript-server/models/User.ts new file mode 100644 index 00000000000..a642d97bf8c --- /dev/null +++ b/samples/server/petstore/typescript-server/models/User.ts @@ -0,0 +1,61 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * A User who is purchasing from the pet store + * @export + * @interface User + */ +export interface User { + /** + * @type {number} + * @memberof User + */ + id?: number; + /** + * @type {string} + * @memberof User + */ + username?: string; + /** + * @type {string} + * @memberof User + */ + firstName?: string; + /** + * @type {string} + * @memberof User + */ + lastName?: string; + /** + * @type {string} + * @memberof User + */ + email?: string; + /** + * @type {string} + * @memberof User + */ + password?: string; + /** + * @type {string} + * @memberof User + */ + phone?: string; + /** + * User Status + * @type {number} + * @memberof User + */ + userStatus?: number; +} diff --git a/samples/server/petstore/typescript-server/models/index.ts b/samples/server/petstore/typescript-server/models/index.ts new file mode 100644 index 00000000000..f53c1dd42bd --- /dev/null +++ b/samples/server/petstore/typescript-server/models/index.ts @@ -0,0 +1,6 @@ +export * from './ApiResponse'; +export * from './Category'; +export * from './Order'; +export * from './Pet'; +export * from './Tag'; +export * from './User'; diff --git a/samples/server/petstore/typescript-server/runtime.ts b/samples/server/petstore/typescript-server/runtime.ts new file mode 100644 index 00000000000..e71a012b04b --- /dev/null +++ b/samples/server/petstore/typescript-server/runtime.ts @@ -0,0 +1,194 @@ +// tslint:disable +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { Observable, of } from 'rxjs'; +import { ajax, AjaxRequest, AjaxResponse } from 'rxjs/ajax'; +import { map, concatMap } from 'rxjs/operators'; + +export const BASE_PATH = 'http://petstore.swagger.io/v2'.replace(/\/+$/, ''); + +export interface ConfigurationParameters { + basePath?: string; // override base path + middleware?: Middleware[]; // middleware to apply before/after rxjs requests + username?: string; // parameter for basic security + password?: string; // parameter for basic security + apiKey?: string | ((name: string) => string); // parameter for apiKey security + accessToken?: string | ((name?: string, scopes?: string[]) => string); // parameter for oauth2 security +} + +export class Configuration { + constructor(private configuration: ConfigurationParameters = {}) {} + + get basePath(): string { + return this.configuration.basePath || BASE_PATH; + } + + get middleware(): Middleware[] { + return this.configuration.middleware || []; + } + + get username(): string | undefined { + return this.configuration.username; + } + + get password(): string | undefined { + return this.configuration.password; + } + + get apiKey(): ((name: string) => string) | undefined { + const apiKey = this.configuration.apiKey; + if (apiKey) { + return typeof apiKey === 'function' ? apiKey : () => apiKey; + } + return undefined; + } + + get accessToken(): ((name: string, scopes?: string[]) => string) | undefined { + const accessToken = this.configuration.accessToken; + if (accessToken) { + return typeof accessToken === 'function' ? accessToken : () => accessToken; + } + return undefined; + } +} + +/** + * This is the base class for all generated API classes. + */ +export class BaseAPI { + private middleware: Middleware[] = []; + + constructor(protected configuration = new Configuration()) { + this.middleware = configuration.middleware; + } + + withMiddleware = (middlewares: Middleware[]) => { + const next = this.clone(); + next.middleware = next.middleware.concat(middlewares); + return next; + }; + + withPreMiddleware = (preMiddlewares: Array) => + this.withMiddleware(preMiddlewares.map((pre) => ({ pre }))); + + withPostMiddleware = (postMiddlewares: Array) => + this.withMiddleware(postMiddlewares.map((post) => ({ post }))); + + protected request = (requestOpts: RequestOpts): Observable => + this.rxjsRequest(this.createRequestArgs(requestOpts)).pipe( + map((res) => { + if (res.status >= 200 && res.status < 300) { + return res.response as T; + } + throw res; + }) + ); + + private createRequestArgs = (requestOpts: RequestOpts): RequestArgs => { + let url = this.configuration.basePath + requestOpts.path; + if (requestOpts.query !== undefined && Object.keys(requestOpts.query).length !== 0) { + // only add the queryString to the URL if there are query parameters. + // this is done to avoid urls ending with a '?' character which buggy webservers + // do not handle correctly sometimes. + url += '?' + queryString(requestOpts.query); + } + + return { + url, + method: requestOpts.method, + headers: requestOpts.headers, + body: requestOpts.body instanceof FormData ? requestOpts.body : JSON.stringify(requestOpts.body), + responseType: requestOpts.responseType || 'json', + }; + } + + private rxjsRequest = (params: RequestArgs): Observable => + of(params).pipe( + map((request) => { + this.middleware.filter((item) => item.pre).forEach((mw) => (request = mw.pre!(request))); + return request; + }), + concatMap((args) => + ajax(args).pipe( + map((response) => { + this.middleware.filter((item) => item.post).forEach((mw) => (response = mw.post!(response))); + return response; + }) + ) + ) + ); + + /** + * Create a shallow clone of `this` by constructing a new instance + * and then shallow cloning data members. + */ + private clone = (): T => + Object.assign(Object.create(Object.getPrototypeOf(this)), this); +} + +// export for not being a breaking change +export class RequiredError extends Error { + name: 'RequiredError' = 'RequiredError'; +} + +export const COLLECTION_FORMATS = { + csv: ',', + ssv: ' ', + tsv: '\t', + pipes: '|', +}; + +export type Json = any; +export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; +export type HttpHeaders = { [key: string]: string }; +export type HttpQuery = Partial<{ [key: string]: string | number | null | boolean | Array }>; // partial is needed for strict mode +export type HttpBody = Json | FormData; +export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; + +export interface RequestOpts { + path: string; + method: HttpMethod; + headers?: HttpHeaders; + query?: HttpQuery; + body?: HttpBody; + responseType?: 'json' | 'blob' | 'arraybuffer' | 'text'; +} + +export const encodeURI = (value: any) => encodeURIComponent(String(value)); + +const queryString = (params: HttpQuery): string => Object.keys(params) + .map((key) => { + const value = params[key]; + return (value instanceof Array) + ? value.map((val) => `${encodeURI(key)}=${encodeURI(val)}`).join('&') + : `${encodeURI(key)}=${encodeURI(value)}`; + }) + .join('&'); + +// alias fallback for not being a breaking change +export const querystring = queryString; + +export const throwIfRequired = (params: {[key: string]: any}, key: string, nickname: string) => { + if (!params || params[key] === null || params[key] === undefined) { + throw new RequiredError(`Required parameter ${key} was null or undefined when calling ${nickname}.`); + } +}; + +// alias for easier importing +export interface RequestArgs extends AjaxRequest {} +export interface ResponseArgs extends AjaxResponse {} + +export interface Middleware { + pre?(request: RequestArgs): RequestArgs; + post?(response: ResponseArgs): ResponseArgs; +} diff --git a/samples/server/petstore/typescript-server/tsconfig.json b/samples/server/petstore/typescript-server/tsconfig.json new file mode 100644 index 00000000000..d65f2a95afc --- /dev/null +++ b/samples/server/petstore/typescript-server/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "declaration": true, + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "outDir": "dist", + "rootDir": ".", + "lib": [ + "es6", + "dom" + ], + "typeRoots": [ + "node_modules/@types" + ] + }, + "exclude": [ + "dist", + "node_modules" + ] +}