decomission nodejs server generator (#6406)

This commit is contained in:
William Cheng
2020-05-23 18:41:52 +08:00
committed by GitHub
parent 950508fd4b
commit 3d0c4e1909
11 changed files with 0 additions and 729 deletions

View File

@@ -103,7 +103,6 @@ The following generators are available:
* [kotlin-spring](generators/kotlin-spring.md)
* [kotlin-vertx (beta)](generators/kotlin-vertx.md)
* [nodejs-express-server (beta)](generators/nodejs-express-server.md)
* [nodejs-server-deprecated (deprecated)](generators/nodejs-server-deprecated.md)
* [php-laravel](generators/php-laravel.md)
* [php-lumen](generators/php-lumen.md)
* [php-silex-deprecated (deprecated)](generators/php-silex-deprecated.md)

View File

@@ -1,479 +0,0 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* 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
*
* https://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 com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.PathItem.HttpMethod;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Info;
import org.openapitools.codegen.*;
import org.openapitools.codegen.config.GlobalSettings;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.utils.URLPathUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import static org.openapitools.codegen.utils.StringUtils.*;
public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(NodeJSServerCodegen.class);
protected String implFolder = "service";
public static final String GOOGLE_CLOUD_FUNCTIONS = "googleCloudFunctions";
public static final String EXPORTED_NAME = "exportedName";
public static final String SERVER_PORT = "serverPort";
protected String apiVersion = "1.0.0";
protected String projectName = "openapi-server";
protected String defaultServerPort = "8080";
protected boolean googleCloudFunctions;
protected String exportedName;
public NodeJSServerCodegen() {
super();
modifyFeatureSet(features -> features
.includeDocumentationFeatures(DocumentationFeature.Readme)
.wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON))
.securityFeatures(EnumSet.noneOf(SecurityFeature.class))
.excludeGlobalFeatures(
GlobalFeature.XMLStructureDefinitions,
GlobalFeature.Callbacks,
GlobalFeature.LinkObjects,
GlobalFeature.ParameterStyling
)
.excludeSchemaSupportFeatures(
SchemaSupportFeature.Polymorphism
)
.excludeParameterFeatures(
ParameterFeature.Cookie
)
);
// mark the generator as deprecated in the documentation
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
.stability(Stability.DEPRECATED)
.build();
// set the output folder here
outputFolder = "generated-code/nodejs";
/*
* Models. You can write model files using the modelTemplateFiles map.
* if you want to create one template for file, you can do so here.
* for multiple files for model, just put another entry in the `modelTemplateFiles` with
* a different extension
*/
modelTemplateFiles.clear();
/*
* Api classes. You can write classes for each Api file with the apiTemplateFiles map.
* as with models, add multiple entries with different extensions for multiple files per
* class
*/
apiTemplateFiles.put(
"controller.mustache", // the template to use
".js"); // the extension for each file to write
/*
* Template Location. This is the location which templates will be read from. The generator
* will use the resource stream to attempt to read the templates.
*/
embeddedTemplateDir = templateDir = "nodejs";
/*
* Reserved words. Override this with reserved words specific to your language
*/
setReservedWordsLowerCase(
Arrays.asList(
"break", "case", "class", "catch", "const", "continue", "debugger",
"default", "delete", "do", "else", "enum", "export", "extends", "finally",
"for", "function", "if", "import", "in", "instanceof", "let", "new",
"return", "super", "switch", "this", "throw", "try", "typeof", "var",
"void", "while", "with", "yield")
);
/*
* Additional Properties. These values can be passed to the templates and
* are available in models, apis, and supporting files
*/
additionalProperties.put("apiVersion", apiVersion);
additionalProperties.put("implFolder", implFolder);
supportingFiles.add(new SupportingFile("writer.mustache", ("utils").replace(".", File.separator), "writer.js"));
cliOptions.add(CliOption.newBoolean(GOOGLE_CLOUD_FUNCTIONS,
"When specified, it will generate the code which runs within Google Cloud Functions "
+ "instead of standalone Node.JS server. See "
+ "https://cloud.google.com/functions/docs/quickstart for the details of how to "
+ "deploy the generated code."));
cliOptions.add(new CliOption(EXPORTED_NAME,
"When the generated code will be deployed to Google Cloud Functions, this option can be "
+ "used to update the name of the exported function. By default, it refers to the "
+ "basePath. This does not affect normal standalone nodejs server code."));
cliOptions.add(new CliOption(SERVER_PORT,
"TCP port to listen on."));
}
@Override
public String apiPackage() {
return "controllers";
}
/**
* Configures the type of generator.
*
* @return the CodegenType for this generator
* @see org.openapitools.codegen.CodegenType
*/
@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}
/**
* Configures a friendly name for the generator. This will be used by the generator
* to select the library with the -g flag.
*
* @return the friendly name for the generator
*/
@Override
public String getName() {
return "nodejs-server-deprecated";
}
/**
* Returns human-friendly help for the generator. Provide the consumer with help
* tips, parameters here
*
* @return A string value for the help message
*/
@Override
public String getHelp() {
return "[DEPRECATED] Generates a nodejs server library using the swagger-tools project. By default, " +
"it will also generate service classes--which you can disable with the `-Dnoservice` environment variable.";
}
@Override
public String toApiName(String name) {
if (name.length() == 0) {
return "DefaultController";
}
return camelize(name);
}
@Override
public String toApiFilename(String name) {
return toApiName(name);
}
@Override
public String apiFilename(String templateName, String tag) {
String result = super.apiFilename(templateName, tag);
if (templateName.equals("service.mustache")) {
String stringToMatch = File.separator + "controllers" + File.separator;
String replacement = File.separator + implFolder + File.separator;
result = result.replaceAll(Pattern.quote(stringToMatch), replacement);
}
return result;
}
private String implFileFolder(String output) {
return outputFolder + File.separator + output + File.separator + apiPackage().replace('.', File.separatorChar);
}
/**
* Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
* those terms here. This logic is only called if a variable matches the reserved words
*
* @return the escaped term
*/
@Override
public String escapeReservedWord(String name) {
if (this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return "_" + name;
}
/**
* Location to write api files. You can use the apiPackage() as defined when the class is
* instantiated
*/
@Override
public String apiFileFolder() {
return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar);
}
public boolean getGoogleCloudFunctions() {
return googleCloudFunctions;
}
public void setGoogleCloudFunctions(boolean value) {
googleCloudFunctions = value;
}
public String getExportedName() {
return exportedName;
}
public void setExportedName(String name) {
exportedName = name;
}
@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
@SuppressWarnings("unchecked")
Map<String, Object> objectMap = (Map<String, Object>) objs.get("operations");
@SuppressWarnings("unchecked")
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
for (CodegenOperation operation : operations) {
operation.httpMethod = operation.httpMethod.toLowerCase(Locale.ROOT);
List<CodegenParameter> params = operation.allParams;
if (params != null && params.size() == 0) {
operation.allParams = null;
}
List<CodegenResponse> responses = operation.responses;
if (responses != null) {
for (CodegenResponse resp : responses) {
if ("0".equals(resp.code)) {
resp.code = "default";
}
}
}
if (operation.examples != null && !operation.examples.isEmpty()) {
// Leave application/json* items only
for (Iterator<Map<String, String>> it = operation.examples.iterator(); it.hasNext(); ) {
final Map<String, String> example = it.next();
final String contentType = example.get("contentType");
if (contentType == null || !contentType.startsWith("application/json")) {
it.remove();
}
}
}
}
return objs;
}
@SuppressWarnings("unchecked")
private static List<Map<String, Object>> getOperations(Map<String, Object> objs) {
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
Map<String, Object> apiInfo = (Map<String, Object>) objs.get("apiInfo");
List<Map<String, Object>> apis = (List<Map<String, Object>>) apiInfo.get("apis");
for (Map<String, Object> api : apis) {
result.add((Map<String, Object>) api.get("operations"));
}
return result;
}
private static List<Map<String, Object>> sortOperationsByPath(List<CodegenOperation> ops) {
Multimap<String, CodegenOperation> opsByPath = ArrayListMultimap.create();
for (CodegenOperation op : ops) {
opsByPath.put(op.path, op);
}
List<Map<String, Object>> opsByPathList = new ArrayList<Map<String, Object>>();
for (Entry<String, Collection<CodegenOperation>> entry : opsByPath.asMap().entrySet()) {
Map<String, Object> opsByPathEntry = new HashMap<String, Object>();
opsByPathList.add(opsByPathEntry);
opsByPathEntry.put("path", entry.getKey());
opsByPathEntry.put("operation", entry.getValue());
List<CodegenOperation> operationsForThisPath = Lists.newArrayList(entry.getValue());
operationsForThisPath.get(operationsForThisPath.size() - 1).hasMore = false;
if (opsByPathList.size() < opsByPath.asMap().size()) {
opsByPathEntry.put("hasMore", "true");
}
}
return opsByPathList;
}
@Override
public void processOpts() {
super.processOpts();
StringBuilder message = new StringBuilder();
message.append(System.lineSeparator()).append(System.lineSeparator())
.append("=======================================================================================")
.append(System.lineSeparator())
.append("IMPORTANT: The nodejs-server generator has been deprecated.")
.append(System.lineSeparator())
.append("Currently, Node.js server doesn't work as its dependency doesn't support OpenAPI Spec3.")
.append(System.lineSeparator())
.append("For further details, see https://github.com/OpenAPITools/openapi-generator/issues/34")
.append(System.lineSeparator())
.append("=======================================================================================")
.append(System.lineSeparator()).append(System.lineSeparator());
LOGGER.warn(message.toString());
if (additionalProperties.containsKey(GOOGLE_CLOUD_FUNCTIONS)) {
setGoogleCloudFunctions(
Boolean.valueOf(additionalProperties.get(GOOGLE_CLOUD_FUNCTIONS).toString()));
}
if (additionalProperties.containsKey(EXPORTED_NAME)) {
setExportedName((String) additionalProperties.get(EXPORTED_NAME));
}
/*
* Supporting Files. You can write single files for the generator with the
* entire object tree available. If the input file has a suffix of `.mustache
* it will be processed by the template engine. Otherwise, it will be copied
*/
// supportingFiles.add(new SupportingFile("controller.mustache",
// "controllers",
// "controller.js")
// );
supportingFiles.add(new SupportingFile("openapi.mustache",
"api",
"openapi.yaml")
);
if (getGoogleCloudFunctions()) {
supportingFiles.add(new SupportingFile("index-gcf.mustache", "", "index.js")
.doNotOverwrite());
} else {
supportingFiles.add(new SupportingFile("index.mustache", "", "index.js")
.doNotOverwrite());
}
supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")
.doNotOverwrite());
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")
.doNotOverwrite());
if (GlobalSettings.getProperty("noservice") == null) {
apiTemplateFiles.put(
"service.mustache", // the template to use
"Service.js"); // the extension for each file to write
}
}
@Override
public void preprocessOpenAPI(OpenAPI openAPI) {
URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
String host = URLPathUtils.getProtocolAndHost(url);
String port = URLPathUtils.getPort(url, defaultServerPort) ;
String basePath = url.getPath();
if (additionalProperties.containsKey(SERVER_PORT)) {
port = additionalProperties.get(SERVER_PORT).toString();
}
this.additionalProperties.put(SERVER_PORT, port);
if (openAPI.getInfo() != null) {
Info info = openAPI.getInfo();
if (info.getTitle() != null) {
// when info.title is defined, use it for projectName
// used in package.json
projectName = info.getTitle()
.replaceAll("[^a-zA-Z0-9]", "-")
.replaceAll("^[-]*", "")
.replaceAll("[-]*$", "")
.replaceAll("[-]{2,}", "-")
.toLowerCase(Locale.ROOT);
this.additionalProperties.put("projectName", projectName);
}
}
if (getGoogleCloudFunctions()) {
// Note that Cloud Functions don't allow customizing port name, simply checking host
// is good enough.
if (!host.endsWith(".cloudfunctions.net")) {
LOGGER.warn("Host " + host + " seems not matching with cloudfunctions.net URL.");
}
if (!additionalProperties.containsKey(EXPORTED_NAME)) {
if (basePath == null || basePath.equals("/")) {
LOGGER.warn("Cannot find the exported name properly. Using 'openapi' as the exported name");
basePath = "/openapi";
}
additionalProperties.put(EXPORTED_NAME, basePath.substring(1));
}
}
// need vendor extensions for x-swagger-router-controller
Paths paths = openAPI.getPaths();
if (paths != null) {
for (String pathname : paths.keySet()) {
PathItem path = paths.get(pathname);
Map<HttpMethod, Operation> operationMap = path.readOperationsMap();
if (operationMap != null) {
for (HttpMethod method : operationMap.keySet()) {
Operation operation = operationMap.get(method);
String tag = "default";
if (operation.getTags() != null && operation.getTags().size() > 0) {
tag = toApiName(operation.getTags().get(0));
}
if (operation.getOperationId() == null) {
operation.setOperationId(getOrGenerateOperationId(operation, pathname, method.toString()));
}
if (operation.getExtensions() == null ||
operation.getExtensions().get("x-swagger-router-controller") == null) {
operation.addExtension("x-swagger-router-controller", sanitizeTag(tag));
}
}
}
}
}
}
@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
generateYAMLSpecFile(objs);
for (Map<String, Object> operations : getOperations(objs)) {
@SuppressWarnings("unchecked")
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
List<Map<String, Object>> opsByPathList = sortOperationsByPath(ops);
operations.put("operationsByPath", opsByPathList);
}
return super.postProcessSupportingFileData(objs);
}
@Override
public String removeNonNameElementToCamelCase(String name) {
return removeNonNameElementToCamelCase(name, "[-:;#]");
}
@Override
public String escapeUnsafeCharacters(String input) {
return input.replace("*/", "*_/").replace("/*", "/_*");
}
@Override
public String escapeQuotationMark(String input) {
// remove " to avoid code injection
return input.replace("\"", "");
}
}

View File

@@ -71,7 +71,6 @@ org.openapitools.codegen.languages.LuaClientCodegen
org.openapitools.codegen.languages.MarkdownDocumentationCodegen
org.openapitools.codegen.languages.MysqlSchemaCodegen
org.openapitools.codegen.languages.NimClientCodegen
org.openapitools.codegen.languages.NodeJSServerCodegen
org.openapitools.codegen.languages.NodeJSExpressServerCodegen
org.openapitools.codegen.languages.ObjcClientCodegen
org.openapitools.codegen.languages.OCamlClientCodegen

View File

@@ -1,27 +0,0 @@
# OpenAPI generated server
## Overview
This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub.
{{^googleCloudFunctions}}
### Running the server
To run the server, run:
```
npm start
```
To view the Swagger UI interface:
```
open http://localhost:{{serverPort}}/docs
```
{{/googleCloudFunctions}}
{{#googleCloudFunctions}}
### Deploying the function
To deploy this module into Google Cloud Functions, you will have to use Google Cloud SDK commandline tool.
See [Google Cloud Functions quick start guide](https://cloud.google.com/functions/docs/quickstart) and [Deploying Cloud Functions](https://cloud.google.com/functions/docs/deploying/) for the details.
{{/googleCloudFunctions}}
This project leverages the mega-awesome [swagger-tools](https://github.com/apigee-127/swagger-tools) middleware which does most all the work.

View File

@@ -1,21 +0,0 @@
'use strict';
var utils = require('../utils/writer.js');
{{#operations}}
var {{classname}} = require('../{{implFolder}}/{{classname}}Service');
{{#operation}}
module.exports.{{nickname}} = function {{nickname}} (req, res, next) {
{{#allParams}}
var {{paramName}} = req.swagger.params['{{baseName}}'].value;
{{/allParams}}
{{classname}}.{{nickname}}({{#allParams}}{{paramName}}{{#hasMore}},{{/hasMore}}{{/allParams}})
.then(function (response) {
utils.writeJson(res, response);
})
.catch(function (response) {
utils.writeJson(res, response);
});
};
{{/operation}}
{{/operations}}

View File

@@ -1,44 +0,0 @@
'use strict';
var swaggerTools = require('swagger-tools');
var jsyaml = require('js-yaml');
var fs = require('fs');
// swaggerRouter configuration
var options = {
controllers: './controllers',
useStubs: false
};
// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
var spec = fs.readFileSync('./api/openapi.yaml', 'utf8');
var swaggerDoc = jsyaml.safeLoad(spec);
function toPromise(f, req, res) {
return new Promise(function(resolve, reject) {
f(req, res, function(err) {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
exports.{{exportedName}} = function(req, res) {
swaggerTools.initializeMiddleware(swaggerDoc, function(middleware) {
var metadata = middleware.swaggerMetadata();
var validator = middleware.swaggerValidator();
var router = middleware.swaggerRouter(options);
req.url = swaggerDoc.basePath + req.url;
toPromise(metadata, req, res).then(function() {
return toPromise(validator, req, res);
}).then(function() {
return toPromise(router, req, res);
}).catch(function(err) {
console.error(err);
res.status(res.statusCode || 400).send(err);
});
});
};

View File

@@ -1,44 +0,0 @@
'use strict';
var fs = require('fs'),
path = require('path'),
http = require('http');
var app = require('connect')();
var swaggerTools = require('swagger-tools');
var jsyaml = require('js-yaml');
var serverPort = {{serverPort}};
// swaggerRouter configuration
var options = {
swaggerUi: path.join(__dirname, '/openapi.json'),
controllers: path.join(__dirname, './controllers'),
useStubs: process.env.NODE_ENV === 'development' // Conditionally turn on stubs (mock mode)
};
// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
var spec = fs.readFileSync(path.join(__dirname,'api/openapi.yaml'), 'utf8');
var swaggerDoc = jsyaml.safeLoad(spec);
// Initialize the Swagger middleware
swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {
// Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
app.use(middleware.swaggerMetadata());
// Validate Swagger requests
app.use(middleware.swaggerValidator());
// Route validated requests to appropriate controller
app.use(middleware.swaggerRouter(options));
// Serve the Swagger documents and Swagger UI
app.use(middleware.swaggerUi());
// Start the server
http.createServer(app).listen(serverPort, function () {
console.log('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort);
console.log('Swagger-ui is available on http://localhost:%d/docs', serverPort);
});
});

View File

@@ -1 +0,0 @@
{{{openapi-yaml}}}

View File

@@ -1,24 +0,0 @@
{
"name": "{{projectName}}",
"version": "{{appVersion}}",
"description": "{{{appDescription}}}",
"main": "index.js",
{{^googleCloudFunctions}}
"scripts": {
"prestart": "npm install",
"start": "node index.js"
},
{{/googleCloudFunctions}}
"keywords": [
"openapi-tools"
],
"license": "Unlicense",
"private": true,
"dependencies": {
{{^googleCloudFunctions}}
"connect": "^3.2.0",
{{/googleCloudFunctions}}
"js-yaml": "^3.3.0",
"swagger-tools": "0.10.1"
}
}

View File

@@ -1,44 +0,0 @@
'use strict';
{{#operations}}
{{#operation}}
/**
{{#summary}}
* {{{summary}}}
{{/summary}}
{{#notes}}
* {{{notes}}}
{{/notes}}
*
{{#allParams}}
* {{paramName}} {{{dataType}}} {{{description}}}{{^required}} (optional){{/required}}
{{/allParams}}
{{^returnType}}
* no response value expected for this operation
{{/returnType}}
{{#returnType}}
* returns {{{returnType}}}
{{/returnType}}
**/
exports.{{{operationId}}} = function({{#allParams}}{{paramName}}{{#hasMore}},{{/hasMore}}{{/allParams}}) {
return new Promise(function(resolve, reject) {
{{#returnType}}
var examples = {};
{{#examples}}
examples['{{contentType}}'] = {{{example}}};
{{/examples}}
if (Object.keys(examples).length > 0) {
resolve(examples[Object.keys(examples)[0]]);
} else {
resolve();
}
{{/returnType}}
{{^returnType}}
resolve();
{{/returnType}}
});
}
{{/operation}}
{{/operations}}

View File

@@ -1,43 +0,0 @@
var ResponsePayload = function(code, payload) {
this.code = code;
this.payload = payload;
}
exports.respondWithCode = function(code, payload) {
return new ResponsePayload(code, payload);
}
var writeJson = exports.writeJson = function(response, arg1, arg2) {
var code;
var payload;
if(arg1 && arg1 instanceof ResponsePayload) {
writeJson(response, arg1.payload, arg1.code);
return;
}
if(arg2 && Number.isInteger(arg2)) {
code = arg2;
}
else {
if(arg1 && Number.isInteger(arg1)) {
code = arg1;
}
}
if(code && arg1) {
payload = arg1;
}
else if(arg1) {
payload = arg1;
}
if(!code) {
// if no response code given, we default to 200
code = 200;
}
if(typeof payload === 'object') {
payload = JSON.stringify(payload, null, 2);
}
response.writeHead(code, {'Content-Type': 'application/json'});
response.end(payload);
}