diff --git a/README.md b/README.md index cae8ada578cc..86497a77c21b 100644 --- a/README.md +++ b/README.md @@ -699,6 +699,7 @@ Here is a list of template creators: * JAX-RS RestEasy (JBoss EAP): @jfiala * Kotlin: @jimschubert [:heart:](https://www.patreon.com/jimschubert) * Kotlin (Spring Boot): @dr4ke616 + * NodeJS Express: @YishTish * PHP Laravel: @renepardon * PHP Lumen: @abcsun * PHP Slim: @jfastnacht diff --git a/docs/generators.md b/docs/generators.md index 5f890cab5bcc..c1203c727a2a 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -91,6 +91,7 @@ The following generators are available: - [jaxrs-spec](generators/jaxrs-spec.md) - [kotlin-server](generators/kotlin-server.md) - [kotlin-spring](generators/kotlin-spring.md) + - [nodejs-express-server](generators/nodejs-express-server.md) (beta) - [nodejs-server-deprecated](generators/nodejs-server-deprecated.md) (deprecated) - [php-laravel](generators/php-laravel.md) - [php-lumen](generators/php-lumen.md) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSExpressServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSExpressServerCodegen.java index d31f52d77b4a..9dec11b8aa07 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSExpressServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NodeJSExpressServerCodegen.java @@ -27,6 +27,8 @@ import io.swagger.v3.oas.models.info.Info; import org.openapitools.codegen.*; import org.openapitools.codegen.config.GeneratorProperties; +import org.openapitools.codegen.meta.GeneratorMetadata; +import org.openapitools.codegen.meta.Stability; import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,49 +44,25 @@ public class NodeJSExpressServerCodegen extends DefaultCodegen implements CodegenConfig { private static final Logger LOGGER = LoggerFactory.getLogger(NodeJSExpressServerCodegen.class); - protected String implFolder = "service"; 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 implFolder = "service"; + protected String projectName = "openapi-server"; protected String exportedName; public NodeJSExpressServerCodegen() { super(); - // 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 + generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata) + .stability(Stability.BETA) + .build(); - /* - * 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"; + outputFolder = "generated-code/nodejs-express-server"; + embeddedTemplateDir = templateDir = "nodejs-express-server"; - /* - * Reserved words. Override this with reserved words specific to your language - */ setReservedWordsLowerCase( Arrays.asList( "break", "case", "class", "catch", "const", "continue", "debugger", @@ -94,19 +72,41 @@ public NodeJSExpressServerCodegen() { "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")); + // no model file + modelTemplateFiles.clear(); + + apiTemplateFiles.put("controller.mustache", ".js"); + apiTemplateFiles.put("service.mustache", ".js"); + + supportingFiles.add(new SupportingFile("openapi.mustache", "api", "openapi.yaml")); + supportingFiles.add(new SupportingFile("app.mustache", "", "app.js")); + supportingFiles.add(new SupportingFile("config.mustache", "", "config.js")); + supportingFiles.add(new SupportingFile("expressServer.mustache", "", "expressServer.js")); + supportingFiles.add(new SupportingFile("index.mustache", "", "index.js")); + supportingFiles.add(new SupportingFile("logger.mustache", "", "logger.js")); + supportingFiles.add(new SupportingFile("eslintrc.mustache", "", ".eslintrc.json")); + + // utils folder + supportingFiles.add(new SupportingFile("utils" + File.separator + "openapiRouter.mustache", "utils", "openapiRouter.js")); + supportingFiles.add(new SupportingFile("utils" + File.separator + "swaggerRouter.mustache", "utils", "swaggerRouter.js")); + supportingFiles.add(new SupportingFile("utils" + File.separator + "writer.mustache", "utils", "writer.js")); + + // controllers folder + supportingFiles.add(new SupportingFile("service" + File.separator + "test.mustache", "controllers", "TestController.js")); + supportingFiles.add(new SupportingFile("controllers" + File.separator + "index.mustache", "controllers", "index.js")); + supportingFiles.add(new SupportingFile("controllers" + File.separator + "Controller.mustache", "controllers", "Controller.js")); + // service folder + supportingFiles.add(new SupportingFile("service" + File.separator + "test.mustache", "service", "TestService.js")); + supportingFiles.add(new SupportingFile("service" + File.separator + "index.mustache", "service", "index.js")); + supportingFiles.add(new SupportingFile("service" + File.separator + "Service.mustache", "service", "Service.js")); + + // do not overwrite if the file is already present + writeOptional(outputFolder, new SupportingFile("package.mustache", "", "package.json")); + writeOptional(outputFolder, new SupportingFile("README.mustache", "", "README.md")); - 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.")); } @@ -146,23 +146,22 @@ public String getName() { */ @Override public String getHelp() { - return "Generates a NodeJS Express server (beta)."; + return "Generates a NodeJS Express server (beta and may subject to breaking changes without further notice)."; } @Override public String toApiName(String name) { if (name.length() == 0) { - return "DefaultController"; + return "Default"; } return camelize(name); } @Override public String toApiFilename(String name) { - return toApiName(name); + return toApiName(name) + "Controller"; } - @Override public String apiFilename(String templateName, String tag) { String result = super.apiFilename(templateName, tag); @@ -171,13 +170,20 @@ public String apiFilename(String templateName, String tag) { String stringToMatch = File.separator + "controllers" + File.separator; String replacement = File.separator + implFolder + File.separator; result = result.replaceAll(Pattern.quote(stringToMatch), replacement); + + stringToMatch = "Controller.js"; + replacement = "Service.js"; + result = result.replaceAll(Pattern.quote(stringToMatch), replacement); } return result; } - private String implFileFolder(String output) { +/* + @Override + protected 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 @@ -202,14 +208,6 @@ 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; } @@ -304,22 +302,6 @@ public void processOpts() { // "controllers", // "controller.js") // ); - supportingFiles.add(new SupportingFile("openapi.mustache", - "api", - "openapi.yaml") - ); - if (getGoogleCloudFunctions()) { - writeOptional(outputFolder, new SupportingFile("index-gcf.mustache", "", "index.js")); - } else { - writeOptional(outputFolder, new SupportingFile("index.mustache", "", "index.js")); - } - writeOptional(outputFolder, new SupportingFile("package.mustache", "", "package.json")); - writeOptional(outputFolder, new SupportingFile("README.mustache", "", "README.md")); - if (GeneratorProperties.getProperty("noservice") == null) { - apiTemplateFiles.put( - "service.mustache", // the template to use - "Service.js"); // the extension for each file to write - } } @Override @@ -349,22 +331,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } - 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 + // need vendor extensions Paths paths = openAPI.getPaths(); if (paths != null) { for (String pathname : paths.keySet()) { @@ -380,14 +347,21 @@ public void preprocessOpenAPI(OpenAPI openAPI) { if (operation.getOperationId() == null) { operation.setOperationId(getOrGenerateOperationId(operation, pathname, method.toString())); } + // add x-openapi-router-controller if (operation.getExtensions() == null || - operation.getExtensions().get("x-swagger-router-controller") == null) { - operation.addExtension("x-swagger-router-controller", sanitizeTag(tag)); + operation.getExtensions().get("x-openapi-router-controller") == null) { + operation.addExtension("x-openapi-router-controller", sanitizeTag(tag) + "Controller"); + } + // add x-openapi-router-service + if (operation.getExtensions() == null || + operation.getExtensions().get("x-openapi-router-service") == null) { + operation.addExtension("x-openapi-router-service", sanitizeTag(tag) + "Service"); } } } } } + } @Override diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/app.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/app.mustache new file mode 100644 index 000000000000..34d7c9c16361 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/app.mustache @@ -0,0 +1,30 @@ +const ExpressServer = require('./expressServer'); +const logger = require('./logger'); +// const swaggerRouter = require('./utils/swaggerRouter'); + +class App { + constructor(config) { + this.config = config; + } + + async launch() { + try { + this.expressServer = new ExpressServer(this.config.URL_PORT, this.config.OPENAPI_YAML); + // this.expressServer.app.use(swaggerRouter()); + await this.expressServer.launch(); + logger.info('Express server running'); + } catch (error) { + logger.error(error); + await this.close(); + } + } + + async close() { + if (this.expressServer !== undefined) { + await this.expressServer.close(); + logger.info(`Server shut down on port ${this.config.URL_PORT}`); + } + } +} + +module.exports = App; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/config.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/config.mustache new file mode 100644 index 000000000000..80f568992bd5 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/config.mustache @@ -0,0 +1,12 @@ +const path = require('path'); + +const config = { + ROOT_DIR: __dirname, + URL_PORT: 3000, + URL_PATH: 'http://localhost', + BASE_VERSION: 'v2', + CONTROLLER_DIRECTORY: path.join(__dirname, 'controllers'), +}; +config.OPENAPI_YAML = path.join(config.ROOT_DIR, 'api', 'openapi.yaml'); +config.FULL_PATH = `${config.URL_PATH}:${config.URL_PORT}/${config.BASE_VERSION}`; +module.exports = config; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/controller.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/controller.mustache index 69ff7249f9da..60a475663d0e 100644 --- a/modules/openapi-generator/src/main/resources/nodejs-express-server/controller.mustache +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/controller.mustache @@ -1,21 +1,17 @@ -'use strict'; +const Controller = require('./Controller'); + +class {{{classname}}}Controller { + constructor(Service) { + this.service = Service; -var utils = require('../utils/writer.js'); {{#operations}} -var {{classname}} = require('../{{implFolder}}/{{classname}}Service'); {{#operation}} + async {{operationId}}(request, response) { + await Controller.handleRequest(request, response, this.service.{{operationId}}); + } -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}} +} + +module.exports = {{classname}}; {{/operations}} diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/Controller.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/Controller.mustache new file mode 100644 index 000000000000..3170c1692d31 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/Controller.mustache @@ -0,0 +1,58 @@ +class Controller { + static sendResponse(response, payload) { + /** + * The default response-code is 200. We want to allow to change that. in That case, + * payload will be an object consisting of a code and a payload. If not customized + * send 200 and the payload as received in this method. + */ + response.status(payload.code || 200); + const responsePayload = payload.payload !== undefined ? payload.payload : payload; + if (responsePayload instanceof Object) { + response.json(responsePayload); + } else { + response.end(responsePayload); + } + } + + static sendError(response, error) { + response.status(error.code || 500); + if (error.error instanceof Object) { + response.json(error.error); + } else { + response.end(error.error || error.message); + } + } + + static collectRequestParams(request) { + const requestParams = {}; + if (request.openapi.schema.requestBody !== undefined) { + requestParams.body = request.body; + } + request.openapi.schema.parameters.forEach((param) => { + if (param.in === 'path') { + requestParams[param.name] = request.openapi.pathParams[param.name]; + } else if (param.in === 'query') { + requestParams[param.name] = request.query[param.name]; + } + }); + return requestParams; + } + + static async handleRequest(request, response, serviceOperation) { + try { + const serviceResponse = await serviceOperation(this.collectRequestParams(request)); + // let serviceResponse; + // this.collectRequestParams(request); + // if (request.openapi.schema.requestBody !== undefined) { + // serviceResponse = await serviceOperation(request.body); + // } else { + // serviceResponse = await serviceOperation(request.openapi.requestParams); + // } + Controller.sendResponse(response, serviceResponse); + } catch (error) { + Controller.sendError(response, error); + } + } +} + +module.exports = Controller; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/index.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/index.mustache new file mode 100644 index 000000000000..5b079e87406f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/index.mustache @@ -0,0 +1,27 @@ +{{#apiInfo}} +{{#apis}} +{{#operations}} +{{#operation}} +{{#-first}} +const {{classname}}Controller = require('./{{classname}}Controller'); +{{/-first}} +{{/operation}} +{{/operations}} +{{/apis}} +{{/apiInfo}} +const TestController = require('./TestController'); + +module.exports = { +{{#apiInfo}} +{{#apis}} +{{#operations}} +{{#operation}} + {{#-first}} + {{classname}}Controller, + {{/-first}} +{{/operation}} +{{/operations}} +{{/apis}} +{{/apiInfo}} + TestController, +}; diff --git a/samples/server/petstore/nodejs-express-server/controllers/Test.js b/modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/test.mustache similarity index 98% rename from samples/server/petstore/nodejs-express-server/controllers/Test.js rename to modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/test.mustache index c7761945ba83..70bb9aa03fb1 100644 --- a/samples/server/petstore/nodejs-express-server/controllers/Test.js +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/controllers/test.mustache @@ -1,6 +1,6 @@ const Controller = require('./Controller'); -class Test { +class TestController { constructor(Service) { this.service = Service; } diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/eslintrc.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/eslintrc.mustache new file mode 100644 index 000000000000..6d8abec4c526 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/eslintrc.mustache @@ -0,0 +1,8 @@ +// Use this file as a starting point for your project's .eslintrc. +// Copy this file, and add rule overrides as needed. +{ + "extends": "airbnb", + "rules": { + "no-console": "off" + } +} diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/expressServer.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/expressServer.mustache new file mode 100644 index 000000000000..5a64ee33a6c8 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/expressServer.mustache @@ -0,0 +1,100 @@ +// const { Middleware } = require('swagger-express-middleware'); +const swaggerUI = require('swagger-ui-express'); +const yamljs = require('yamljs'); +const express = require('express'); +const cors = require('cors'); +const cookieParser = require('cookie-parser'); +const bodyParser = require('body-parser'); +const { OpenApiValidator } = require('express-openapi-validator'); +const swaggerRouter = require('./utils/swaggerRouter'); + + +class ExpressServer { + constructor(port, openApiYaml) { + this.port = port; + this.app = express(); + this.schema = openApiYaml; + // this.middleware = new Middleware(this.app); + this.setupMiddleware(); + } + + setupMiddleware() { + this.app.use(cors()); + this.app.use(bodyParser.json()); + this.app.use(express.json()); + this.app.use(express.urlencoded({ extended: false })); + this.app.use(cookieParser()); + this.app.get('/spec', express.static(this.schema)); + this.app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(yamljs.load(this.schema))); + this.app.get('/login-redirect', (req, res) => { + res.status(200); + res.json(req.query); + }); + this.app.get('/oauth2-redirect.html', (req, res) => { + res.status(200); + res.json(req.query); + }); + new OpenApiValidator({ + apiSpecPath: this.schema, + }).install(this.app); + this.app.use(swaggerRouter()); + // this.middleware.init(this.schema, (err) => { + // if (err) { + // console.error(err); + // } + // }); + // this.app.use( + // // this.middleware.metadata(), + // // this.middleware.CORS(), + // // this.middleware.parseRequest(), + // // this.middleware.validateRequest(), + // // ('/api-docs', swaggerUI.serve, swaggerUI.setup(this.swaggerJson)), + // ); + this.app.get('/', (req, res) => { + res.status(200); + res.end('Hello World'); + }); + } + + addErrorHandler() { + this.app.use('*', (req, res) => { + res.status(404); + res.send(JSON.stringify({ error: `path ${req.baseUrl} doesn't exist` })); + }); + /** + * suppressed eslint rule: The next variable is required here, even though it's not used. + * + ** */ + // eslint-disable-next-line no-unused-vars + this.app.use((error, req, res, next) => { + const errorResponse = error.error || error.errors || error.message || 'Unknown error'; + res.status(error.status || 500); + res.type('json'); + res.json({ error: errorResponse }); + }); + } + + async launch() { + return new Promise( + async (resolve, reject) => { + try { + this.addErrorHandler(); + this.server = await this.app.listen(this.port, () => { + console.log(`server running on port ${this.port}`); + resolve(this.server); + }); + } catch (error) { + reject(error); + } + }, + ); + } + + async close() { + if (this.server !== undefined) { + await this.server.close(); + console.log(`Server on port ${this.port} shut down`); + } + } +} +module.exports = ExpressServer; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/index-gcf.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/index-gcf.mustache deleted file mode 100644 index 6cf3a5a5c1c1..000000000000 --- a/modules/openapi-generator/src/main/resources/nodejs-express-server/index-gcf.mustache +++ /dev/null @@ -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); - }); - }); -}; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/index.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/index.mustache index b0054f883c2f..731c79aa051b 100644 --- a/modules/openapi-generator/src/main/resources/nodejs-express-server/index.mustache +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/index.mustache @@ -1,44 +1,15 @@ -'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); +const config = require('./config'); +const logger = require('./logger'); +const App = require('./app'); + +const app = new App(config); +app.launch() + .then(() => { + logger.info('Server launched'); + }) + .catch((error) => { + logger.error('found error, shutting down server'); + app.close() + .catch(closeError => logger.error(closeError)) + .finally(() => logger.error(error)); }); - -}); diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/logger.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/logger.mustache new file mode 100644 index 000000000000..27134586f8e5 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/logger.mustache @@ -0,0 +1,17 @@ +const winston = require('winston'); + +const logger = winston.createLogger({ + level: 'info', + format: winston.format.json(), + defaultMeta: { service: 'user-service' }, + transports: [ + new winston.transports.File({ filename: 'error.log', level: 'error' }), + new winston.transports.File({ filename: 'combined.log' }), + ], +}); + +if (process.env.NODE_ENV !== 'production') { + logger.add(new winston.transports.Console({ format: winston.format.simple() })); +} + +module.exports = logger; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/package.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/package.mustache index 1dc5cb90f1de..18e7d92069f9 100644 --- a/modules/openapi-generator/src/main/resources/nodejs-express-server/package.mustache +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/package.mustache @@ -1,24 +1,39 @@ { - "name": "{{projectName}}", - "version": "{{appVersion}}", - "description": "{{{appDescription}}}", + "name": "openapi-petstore", + "version": "1.0.0", + "description": "This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.", "main": "index.js", - {{^googleCloudFunctions}} "scripts": { "prestart": "npm install", "start": "node index.js" }, - {{/googleCloudFunctions}} "keywords": [ - "openapi-tools" + "openapi-generator", "openapi" ], "license": "Unlicense", "private": true, "dependencies": { - {{^googleCloudFunctions}} + "body-parser": "^1.19.0", "connect": "^3.2.0", - {{/googleCloudFunctions}} + "cookie-parser": "^1.4.4", + "cors": "^2.8.5", + "express": "^4.16.4", + "express-openapi-validator": "^1.0.0", "js-yaml": "^3.3.0", - "swagger-tools": "0.10.1" + "swagger-express-middleware": "^2.0.2", + "swagger-tools": "^0.10.4", + "swagger-ui-express": "^4.0.2", + "winston": "^3.2.1", + "yamljs": "^0.3.0" + }, + "devDependencies": { + "axios": "^0.19.0", + "chai": "^4.2.0", + "chai-as-promised": "^7.1.1", + "eslint": "^5.16.0", + "eslint-config-airbnb-base": "^13.1.0", + "eslint-plugin-import": "^2.17.2", + "form-data": "^2.3.3", + "mocha": "^6.1.4" } } diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/service.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/service.mustache index 90d354b1a14a..07667d84d5ec 100644 --- a/modules/openapi-generator/src/main/resources/nodejs-express-server/service.mustache +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/service.mustache @@ -1,44 +1,45 @@ -'use strict'; +/* eslint-disable no-unused-vars */ +const Service = require('./Service'); + +class {{{classname}}}Service { {{#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) { + /** + {{#summary}} + * {{{summary}}} + {{/summary}} + {{#notes}} + * {{{notes}}} + {{/notes}} + * + {{#allParams}} + * {{paramName}} {{{dataType}}} {{{description}}}{{^required}} (optional){{/required}} + {{/allParams}} + {{^returnType}} + * no response value expected for this operation + {{/returnType}} {{#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}} - }); -} + * returns {{{returnType}}} + {{/returnType}} + **/ + static.{{{operationId}}}({ {{#allParams}}{{paramName}}{{#hasMore}},{{/hasMore}}{{/allParams}} }) { + return new Promise( + async (resolve) => { + try { + resolve(Service.successResponse('')); + } catch (e) { + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } {{/operation}} +} + +module.exports = {{{classname}}}Service; {{/operations}} diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/service/Service.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/service/Service.mustache new file mode 100644 index 000000000000..11f8c9a1c3ab --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/service/Service.mustache @@ -0,0 +1,11 @@ +class Service { + static rejectResponse(error, code = 500) { + return { error, code }; + } + + static successResponse(payload, code = 200) { + return { payload, code }; + } +} + +module.exports = Service; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/service/index.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/service/index.mustache new file mode 100644 index 000000000000..4a122c0a2496 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/service/index.mustache @@ -0,0 +1,27 @@ +{{#apiInfo}} +{{#apis}} +{{#operations}} +{{#operation}} +{{#-first}} +const {{classname}}Service = require('./{{classname}}Service'); +{{/-first}} +{{/operation}} +{{/operations}} +{{/apis}} +{{/apiInfo}} +const TestService = require('./TestService'); + +module.exports = { +{{#apiInfo}} +{{#apis}} +{{#operations}} +{{#operation}} +{{#-first}} + {{classname}}Service, +{{/-first}} +{{/operation}} +{{/operations}} +{{/apis}} +{{/apiInfo}} + TestService, +}; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/service/test.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/service/test.mustache new file mode 100644 index 000000000000..8ecd49dbf89b --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/service/test.mustache @@ -0,0 +1,113 @@ +const Service = require('./Service'); + +const testItems = require('../tests/testFiles/testItems.json'); + +class TestService { + static testGetController() { + return new Promise( + async (resolve, reject) => { + try { + resolve(Service.successResponse( + testItems, + 200, + )); + } catch (e) { + const message = e.getMessage() || 'Could not get items. Server error'; + reject(Service.rejectResponse(message, 500)); + } + }, + ); + } + + static testDeleteController({ itemId }) { + return new Promise( + async (resolve, reject) => { + try { + let responseMessage = ''; + const itemToDeleteIndex = testItems.findIndex(item => item.id === itemId); + if (itemToDeleteIndex > -1) { + testItems.splice(itemToDeleteIndex, 1); + responseMessage = `test item id ${itemId} deleted successfully`; + } else { + responseMessage = 'test item not found, nothing changed'; + } + resolve(Service.successResponse(responseMessage, 200)); + } catch (err) { + const message = err.getMessage() || 'Invalid test item value'; + const code = err.status || 400; + reject(Service.rejectResponse(message, code)); + } + }, + ); + } + + static testPostController({ testItem }) { + return new Promise( + async (resolve, reject) => { + try { + const highestId = testItems[testItems.length - 1].id; + const newItem = { + id: highestId + 1, + name: testItem.name, + description: testItem.description, + version: testItem.version, + }; + testItems.push(newItem); + resolve(Service.successResponse(newItem)); + } catch (e) { + reject(Service.rejectResponse( + e.getMessage() || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } + + static testFindByIdController({ itemId }) { + return new Promise( + async (resolve, reject) => { + try { + const itemFound = testItems.find(item => item.id === itemId); + if (itemFound !== undefined) { + resolve(Service.successResponse(itemFound, 200)); + } else { + reject(Service.rejectResponse('item not found', 404)); + } + } catch (e) { + reject(Service.rejectResponse(e.getMessage() || 'Invalid ID supplied', 400)); + } + }, + ); + } + + static testPutController({ itemId, testItem }) { + return new Promise( + async (resolve, reject) => { + try { + let responseBody; + const itemToUpdate = testItems.find(item => item.id === itemId); + if (itemToUpdate !== undefined) { + itemToUpdate.name = testItem.name || itemToUpdate.name; + itemToUpdate.description = testItem.description || itemToUpdate.description; + itemToUpdate.version = testItem.version || itemToUpdate.version; + responseBody = itemToUpdate; + } else { + responseBody = `could not find an item with id ${itemId} to update. Nothing changed`; + } + resolve(Service.successResponse( + responseBody, + 200, + )); + } catch (e) { + reject(Service.rejectResponse( + e.getMessage || 'Invalid input', + 405, + )); + } + }, + ); + } +} + +module.exports = TestService; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/utils/openapiRouter.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/utils/openapiRouter.mustache new file mode 100644 index 000000000000..ae4fd17383f0 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/utils/openapiRouter.mustache @@ -0,0 +1,11 @@ +class OpenapiRouter { + constructor(openApiDoc) { + this.apiDoc = openApiDoc; + } + + loadSchemas() { + console.log(this.apiDoc); + } +} + +module.exports = OpenapiRouter; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/utils/swaggerRouter.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/utils/swaggerRouter.mustache new file mode 100644 index 000000000000..530bbb7d3a6b --- /dev/null +++ b/modules/openapi-generator/src/main/resources/nodejs-express-server/utils/swaggerRouter.mustache @@ -0,0 +1,65 @@ +const logger = require('../logger'); +const controllers = require('../controllers'); +const Services = require('../service'); + +function handleError(err, request, response, next) { + logger.error(err); + const code = err.code || 400; + response.status(code); + response.error = err; + next(JSON.stringify({ + code, + error: err, + })); +} + +/** + * The purpose of this route is to collect the request variables as defined in the + * Swagger/OpenAPI document and pass them to the handling controller as another Express + * middleware. All parameters are collected in the requet.swagger.values key-value object + * + * The assumption is that security handlers have already verified and allowed access + * to this path. If the business-logic of a particular path is dependant on authentication + * parameters (e.g. scope checking) - it is recommended to define the authentication header + * as one of the parameters expected in the OpenAPI/Swagger document. + * + * Requests made to paths that are not in the OpernAPI/Swagger scope + * are passed on to the next middleware handler. + * @returns {Function} + */ +function swaggerRouter() { + return async (request, response, next) => { + try { + /** + * Previous process should have applied an openapi object to the request. If none was applied + * This is because the path requested is not in the schema. Nothing to do here. + */ + if (request.openapi === undefined + || request.openapi.schema === undefined + ) { + next(); + return; + } + // request.swagger.paramValues = {}; + // request.swagger.params.forEach((param) => { + // request.swagger.paramValues[param.name] = getValueFromRequest(request, param); + // }); + const controllerName = request.openapi.schema['x-openapi-router-controller']; + const serviceName = `${controllerName}Service`; + if (!controllers[controllerName] || controllers[controllerName] === undefined) { + handleError(`request sent to controller '${controllerName}' which has not been defined`, + request, response, next); + } else { + const apiController = new controllers[controllerName](Services[serviceName]); + const controllerOperation = request.openapi.schema.operationId; + await apiController[controllerOperation](request, response, next); + } + } catch (error) { + console.error(error); + const err = { code: 500, error: error.message }; + handleError(err, request, response, next); + } + }; +} + +module.exports = swaggerRouter; diff --git a/modules/openapi-generator/src/main/resources/nodejs-express-server/writer.mustache b/modules/openapi-generator/src/main/resources/nodejs-express-server/utils/writer.mustache similarity index 100% rename from modules/openapi-generator/src/main/resources/nodejs-express-server/writer.mustache rename to modules/openapi-generator/src/main/resources/nodejs-express-server/utils/writer.mustache diff --git a/samples/server/petstore/nodejs-express-server/.eslintrc.json b/samples/server/petstore/nodejs-express-server/.eslintrc.json new file mode 100644 index 000000000000..6d8abec4c526 --- /dev/null +++ b/samples/server/petstore/nodejs-express-server/.eslintrc.json @@ -0,0 +1,8 @@ +// Use this file as a starting point for your project's .eslintrc. +// Copy this file, and add rule overrides as needed. +{ + "extends": "airbnb", + "rules": { + "no-console": "off" + } +} diff --git a/samples/server/petstore/nodejs-express-server/.openapi-generator/VERSION b/samples/server/petstore/nodejs-express-server/.openapi-generator/VERSION index 717311e32e3c..479c313e87b9 100644 --- a/samples/server/petstore/nodejs-express-server/.openapi-generator/VERSION +++ b/samples/server/petstore/nodejs-express-server/.openapi-generator/VERSION @@ -1 +1 @@ -unset \ No newline at end of file +4.0.3-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/nodejs-express-server/README.md b/samples/server/petstore/nodejs-express-server/README.md index c9eece72c786..83854914e63a 100644 --- a/samples/server/petstore/nodejs-express-server/README.md +++ b/samples/server/petstore/nodejs-express-server/README.md @@ -1,106 +1,19 @@ -##nodejs-express-server -This module is an update to the nodejs-server module for auto-generating the infrastructure of swagger/openapi based projects. This module creates an environment based on express.js, using updated node modules and conventions. -#####prerequesits: -Node.js => 8.9.* +# OpenAPI generated server -Currently, this module generates code based on Swagger v2 yaml documents only. OpenApi v3 will be supported soon after v2 is up and running. +## 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. -At this point there's no support for security handling. Once the routing and the regular +### Running the server +To run the server, run: -This module contains the following directories/files: +``` +npm start +``` -###### .eslintrc -JavaScript linter, extending the airbnb specification, with one change - allowing for console usage. +To view the Swagger UI interface: -###### README.md - This file - -###### app.js -This is where application launches - it imports our express implementation and our Swagger/OpenAPI router and launches the server. - -###### config.js -Configuration file. Note that this is a js file, with code and slight business-logic and not a straight json file - -###### expressServer.js -Our implementation of the express server, together with the needed 3rd-party libraries, except for our routing and security middleware - Those are currently loaded in app.js. In the future we might join app.js and expressServer.js) - -###### index.js -Our 'main' file. Kept to minimum size, to allow least dependency. Separating `index.js` and `app.js` allows us to launch the same application with the same code, while changing only the configuration file, thus keeping maximum consistency between environments. - -###### logger.js -This project uses `winston` for logging. This file loads the configuration setup for logging. _todo_: logger is now similar for all environments, all files import the same logger file, with the same settings for all environments. - -######package.json -_npm_ installation and dependency file. - - - -###/api - -######openapi.yaml -sample file, for future use - -######swagger.yaml -Project API code is generated based on this file - -###/controllers -automatically generated directory - -######Controller.js -Parent class, contains code for handling interaction between controller and service classes, and serving back to the client (user) the response (or failure) generated by back-end code. - -######Pet.js -New format for controllers. Use this to auto-generate controller files, based on api/swagger.yaml. Every path operation has a field `x-swagger-router-controller`, which is the name of the Controller file, and `operationId` is the name of the method. The method receives `request` and `response` as parameters, and sends those, together with the name of the handling service method to the general `Controller.js` file for future handling. - -######Store.js, User.js -Old format for controllers. This is what is generated with current codegen - -######Test.js -Test controller file. It's here temporarily. Eventually it will move to a dedicated directory, and if/when people want to test the system, they will be able to place this test file here and run the tests written to verify the routing process works. - -######index.js -A new auto-generated file. Imports all the controllers, and exports an object referencing every controller that was imported. - - -### /service -Auto generated directory - -###### PetService.js -New format of API services. This is a bit more complicated than the controllers generation. The broad logic is similar - yaml paths and operation have `x-swagger-router-controller` for the name of the class/file, and files have methods based on the operationId. Methods receive as arguments the parameters defined in the yaml file, as object members (JavaScript has a shorthand operation where you just type the name of the variable, and it will populate it's value autormtically). - -The generation of this file is a bit tricky because we want to deliver stub output based on what is written in the yaml file - is a success response an object or a string? maybe binary? We also want to provide a stub for error responses. - -###### Service.js -Parent service class, containing 2 methods for handling successful or failed processes. These are the methods that send back the response to the controller, and from there back to the client. At this point this file is a bit empty, but allows for changes in the future. - -###### StoreService.js, UserService.js -Old format service files. - -###### TestService.js -Test file. Located here temporarily. Test validating this project run through this service. In the future, this file will be located in a separate directory, with a possibility to import for those who want to run tests. - -###### index.js -Auto generated. Like `index.js` in the `controllers` directory, this is the main file of the `services` directory. This file imports all the services in the directory, and exports an object referencing to all the imported files. - -### /tests -All tests are written here. This directory also contains all the necessary files needed in order to run tests - temporary files, configuration files, etc. - -- SwaggerRouterTests.js -- config.js -- logger.js -- serverTests.js -- swaggerControllerTests.js -##### /tests/testFiles -- images.png -- pet.json -- swagger.yaml -- testItems.json - -### /utils -This is a temporary directory. Will be removed once the files make it to the npm repository and are loaded as part of the npm installation process -###### swaggerRouter.js -This project is depending on 3rd-party library `swagger-express-middleware`. This library does all the validation and processing, except for routing to the controllers generated by this project. `swaggerRouter.js` implements that last leg - collecting the data that was passed and validates this far, and passing it to the relevant controller method. - -###### writer.js -Old and obsolete file. Will be removed in the near future. +``` +open http://localhost:8080/docs +``` +This project leverages the mega-awesome [swagger-tools](https://github.com/apigee-127/swagger-tools) middleware which does most all the work. diff --git a/samples/server/petstore/nodejs-express-server/api/openapi.yaml b/samples/server/petstore/nodejs-express-server/api/openapi.yaml index d8538697d4ac..401e628f3bd1 100644 --- a/samples/server/petstore/nodejs-express-server/api/openapi.yaml +++ b/samples/server/petstore/nodejs-express-server/api/openapi.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.1 +openapi: 3.0.1 info: description: This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. @@ -8,7 +8,7 @@ info: title: OpenAPI Petstore version: 1.0.0 servers: -- url: http://localhost:3000/v2 +- url: http://petstore.swagger.io/v2 tags: - description: Everything about your Pets name: pet @@ -41,7 +41,9 @@ paths: summary: Add a new pet to the store tags: - pet - x-openapi-router-controller: Pet + x-codegen-request-body-name: body + x-openapi-router-controller: PetController + x-openapi-router-service: PetService put: operationId: updatePet requestBody: @@ -71,7 +73,9 @@ paths: summary: Update an existing pet tags: - pet - x-openapi-router-controller: Pet + x-codegen-request-body-name: body + x-openapi-router-controller: PetController + x-openapi-router-service: PetService /pet/findByStatus: get: description: Multiple status values can be provided with comma separated strings @@ -116,7 +120,8 @@ paths: summary: Finds Pets by status tags: - pet - x-openapi-router-controller: Pet + x-openapi-router-controller: PetController + x-openapi-router-service: PetService /pet/findByTags: get: deprecated: true @@ -158,7 +163,8 @@ paths: summary: Finds Pets by tags tags: - pet - x-openapi-router-controller: Pet + x-openapi-router-controller: PetController + x-openapi-router-service: PetService /pet/{petId}: delete: operationId: deletePet @@ -185,7 +191,8 @@ paths: summary: Deletes a pet tags: - pet - x-openapi-router-controller: Pet + x-openapi-router-controller: PetController + x-openapi-router-service: PetService get: description: Returns a single pet operationId: getPetById @@ -218,7 +225,8 @@ paths: summary: Find pet by ID tags: - pet - x-openapi-router-controller: Pet + x-openapi-router-controller: PetController + x-openapi-router-service: PetService post: operationId: updatePetWithForm parameters: @@ -251,7 +259,8 @@ paths: summary: Updates a pet in the store with form data tags: - pet - x-openapi-router-controller: Pet + x-openapi-router-controller: PetController + x-openapi-router-service: PetService /pet/{petId}/uploadImage: post: operationId: uploadFile @@ -289,7 +298,8 @@ paths: summary: uploads an image tags: - pet - x-openapi-router-controller: Pet + x-openapi-router-controller: PetController + x-openapi-router-service: PetService /store/inventory: get: description: Returns a map of status codes to quantities @@ -309,7 +319,8 @@ paths: summary: Returns pet inventories by status tags: - store - x-openapi-router-controller: Store + x-openapi-router-controller: StoreController + x-openapi-router-service: StoreService /store/order: post: operationId: placeOrder @@ -337,7 +348,8 @@ paths: tags: - store x-codegen-request-body-name: body - x-openapi-router-controller: Store + x-openapi-router-controller: StoreController + x-openapi-router-service: StoreService /store/order/{orderId}: delete: description: For valid response try integer IDs with value < 1000. Anything @@ -360,7 +372,8 @@ paths: summary: Delete purchase order by ID tags: - store - x-openapi-router-controller: Store + x-openapi-router-controller: StoreController + x-openapi-router-service: StoreService get: description: For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions @@ -394,7 +407,8 @@ paths: summary: Find purchase order by ID tags: - store - x-openapi-router-controller: Store + x-openapi-router-controller: StoreController + x-openapi-router-service: StoreService /user: post: description: This can only be done by the logged in user. @@ -414,7 +428,8 @@ paths: tags: - user x-codegen-request-body-name: body - x-openapi-router-controller: User + x-openapi-router-controller: UserController + x-openapi-router-service: UserService /user/createWithArray: post: operationId: createUsersWithArrayInput @@ -435,7 +450,8 @@ paths: tags: - user x-codegen-request-body-name: body - x-openapi-router-controller: User + x-openapi-router-controller: UserController + x-openapi-router-service: UserService /user/createWithList: post: operationId: createUsersWithListInput @@ -456,7 +472,8 @@ paths: tags: - user x-codegen-request-body-name: body - x-openapi-router-controller: User + x-openapi-router-controller: UserController + x-openapi-router-service: UserService /user/login: get: operationId: loginUser @@ -500,7 +517,8 @@ paths: summary: Logs user into the system tags: - user - x-openapi-router-controller: User + x-openapi-router-controller: UserController + x-openapi-router-service: UserService /user/logout: get: operationId: logoutUser @@ -511,7 +529,8 @@ paths: summary: Logs out current logged in user session tags: - user - x-openapi-router-controller: User + x-openapi-router-controller: UserController + x-openapi-router-service: UserService /user/{username}: delete: description: This can only be done by the logged in user. @@ -533,7 +552,8 @@ paths: summary: Delete user tags: - user - x-openapi-router-controller: User + x-openapi-router-controller: UserController + x-openapi-router-service: UserService get: operationId: getUserByName parameters: @@ -562,7 +582,8 @@ paths: summary: Get user by user name tags: - user - x-openapi-router-controller: User + x-openapi-router-controller: UserController + x-openapi-router-service: UserService put: description: This can only be done by the logged in user. operationId: updateUser @@ -591,7 +612,8 @@ paths: tags: - user x-codegen-request-body-name: body - x-openapi-router-controller: User + x-openapi-router-controller: UserController + x-openapi-router-service: UserService components: schemas: Order: @@ -769,7 +791,7 @@ components: petstore_auth: flows: implicit: - authorizationUrl: "https://dev-510693.oktapreview.com/oauth2/auslj77udsWHzNaam0h7/v1/authorize" + authorizationUrl: http://petstore.swagger.io/api/oauth/dialog scopes: write:pets: modify pets in your account read:pets: read your pets diff --git a/samples/server/petstore/nodejs-express-server/controllers/Pet.js b/samples/server/petstore/nodejs-express-server/controllers/PetController.js similarity index 98% rename from samples/server/petstore/nodejs-express-server/controllers/Pet.js rename to samples/server/petstore/nodejs-express-server/controllers/PetController.js index 31ad2ecd6950..d775f5f104d1 100644 --- a/samples/server/petstore/nodejs-express-server/controllers/Pet.js +++ b/samples/server/petstore/nodejs-express-server/controllers/PetController.js @@ -1,9 +1,8 @@ const Controller = require('./Controller'); -class Pet { +class PetController { constructor(Service) { this.service = Service; - } async addPet(request, response) { await Controller.handleRequest(request, response, this.service.addPet); @@ -36,6 +35,7 @@ class Pet { async uploadFile(request, response) { await Controller.handleRequest(request, response, this.service.uploadFile); } + } module.exports = Pet; diff --git a/samples/server/petstore/nodejs-express-server/controllers/Store.js b/samples/server/petstore/nodejs-express-server/controllers/Store.js deleted file mode 100644 index b781e64556fd..000000000000 --- a/samples/server/petstore/nodejs-express-server/controllers/Store.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -var utils = require('../utils/writer.js'); -var Store = require('../service/StoreService'); - -module.exports.deleteOrder = function deleteOrder (req, res, next) { - var orderId = req.swagger.params['orderId'].value; - Store.deleteOrder(orderId) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (response) { - utils.writeJson(res, response); - }); -}; - -module.exports.getInventory = function getInventory (req, res, next) { - Store.getInventory() - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (response) { - utils.writeJson(res, response); - }); -}; - -module.exports.getOrderById = function getOrderById (req, res, next) { - var orderId = req.swagger.params['orderId'].value; - Store.getOrderById(orderId) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (response) { - utils.writeJson(res, response); - }); -}; - -module.exports.placeOrder = function placeOrder (req, res, next) { - var body = req.swagger.params['body'].value; - Store.placeOrder(body) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (response) { - utils.writeJson(res, response); - }); -}; diff --git a/samples/server/petstore/nodejs-express-server/controllers/StoreController.js b/samples/server/petstore/nodejs-express-server/controllers/StoreController.js new file mode 100644 index 000000000000..cd6e7b078a84 --- /dev/null +++ b/samples/server/petstore/nodejs-express-server/controllers/StoreController.js @@ -0,0 +1,25 @@ +const Controller = require('./Controller'); + +class StoreController { + constructor(Service) { + this.service = Service; + + async deleteOrder(request, response) { + await Controller.handleRequest(request, response, this.service.deleteOrder); + } + + async getInventory(request, response) { + await Controller.handleRequest(request, response, this.service.getInventory); + } + + async getOrderById(request, response) { + await Controller.handleRequest(request, response, this.service.getOrderById); + } + + async placeOrder(request, response) { + await Controller.handleRequest(request, response, this.service.placeOrder); + } + +} + +module.exports = Store; diff --git a/samples/server/petstore/nodejs-express-server/controllers/TestController.js b/samples/server/petstore/nodejs-express-server/controllers/TestController.js new file mode 100644 index 000000000000..8ecd49dbf89b --- /dev/null +++ b/samples/server/petstore/nodejs-express-server/controllers/TestController.js @@ -0,0 +1,113 @@ +const Service = require('./Service'); + +const testItems = require('../tests/testFiles/testItems.json'); + +class TestService { + static testGetController() { + return new Promise( + async (resolve, reject) => { + try { + resolve(Service.successResponse( + testItems, + 200, + )); + } catch (e) { + const message = e.getMessage() || 'Could not get items. Server error'; + reject(Service.rejectResponse(message, 500)); + } + }, + ); + } + + static testDeleteController({ itemId }) { + return new Promise( + async (resolve, reject) => { + try { + let responseMessage = ''; + const itemToDeleteIndex = testItems.findIndex(item => item.id === itemId); + if (itemToDeleteIndex > -1) { + testItems.splice(itemToDeleteIndex, 1); + responseMessage = `test item id ${itemId} deleted successfully`; + } else { + responseMessage = 'test item not found, nothing changed'; + } + resolve(Service.successResponse(responseMessage, 200)); + } catch (err) { + const message = err.getMessage() || 'Invalid test item value'; + const code = err.status || 400; + reject(Service.rejectResponse(message, code)); + } + }, + ); + } + + static testPostController({ testItem }) { + return new Promise( + async (resolve, reject) => { + try { + const highestId = testItems[testItems.length - 1].id; + const newItem = { + id: highestId + 1, + name: testItem.name, + description: testItem.description, + version: testItem.version, + }; + testItems.push(newItem); + resolve(Service.successResponse(newItem)); + } catch (e) { + reject(Service.rejectResponse( + e.getMessage() || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } + + static testFindByIdController({ itemId }) { + return new Promise( + async (resolve, reject) => { + try { + const itemFound = testItems.find(item => item.id === itemId); + if (itemFound !== undefined) { + resolve(Service.successResponse(itemFound, 200)); + } else { + reject(Service.rejectResponse('item not found', 404)); + } + } catch (e) { + reject(Service.rejectResponse(e.getMessage() || 'Invalid ID supplied', 400)); + } + }, + ); + } + + static testPutController({ itemId, testItem }) { + return new Promise( + async (resolve, reject) => { + try { + let responseBody; + const itemToUpdate = testItems.find(item => item.id === itemId); + if (itemToUpdate !== undefined) { + itemToUpdate.name = testItem.name || itemToUpdate.name; + itemToUpdate.description = testItem.description || itemToUpdate.description; + itemToUpdate.version = testItem.version || itemToUpdate.version; + responseBody = itemToUpdate; + } else { + responseBody = `could not find an item with id ${itemId} to update. Nothing changed`; + } + resolve(Service.successResponse( + responseBody, + 200, + )); + } catch (e) { + reject(Service.rejectResponse( + e.getMessage || 'Invalid input', + 405, + )); + } + }, + ); + } +} + +module.exports = TestService; diff --git a/samples/server/petstore/nodejs-express-server/controllers/User.js b/samples/server/petstore/nodejs-express-server/controllers/UserController.js similarity index 62% rename from samples/server/petstore/nodejs-express-server/controllers/User.js rename to samples/server/petstore/nodejs-express-server/controllers/UserController.js index 599811d5ef27..7b30fff626b5 100644 --- a/samples/server/petstore/nodejs-express-server/controllers/User.js +++ b/samples/server/petstore/nodejs-express-server/controllers/UserController.js @@ -1,16 +1,19 @@ const Controller = require('./Controller'); -class User { +class UserController { constructor(Service) { this.service = Service; + + async createUser(request, response) { + await Controller.handleRequest(request, response, this.service.createUser); } - async loginUser(request, response) { - await Controller.handleRequest(request, response, this.service.loginUser); + async createUsersWithArrayInput(request, response) { + await Controller.handleRequest(request, response, this.service.createUsersWithArrayInput); } - async logoutUser(request, response) { - await Controller.handleRequest(request, response, this.service.logoutUser); + async createUsersWithListInput(request, response) { + await Controller.handleRequest(request, response, this.service.createUsersWithListInput); } async deleteUser(request, response) { @@ -21,9 +24,18 @@ class User { await Controller.handleRequest(request, response, this.service.getUserByName); } + async loginUser(request, response) { + await Controller.handleRequest(request, response, this.service.loginUser); + } + + async logoutUser(request, response) { + await Controller.handleRequest(request, response, this.service.logoutUser); + } + async updateUser(request, response) { await Controller.handleRequest(request, response, this.service.updateUser); } + } module.exports = User; diff --git a/samples/server/petstore/nodejs-express-server/controllers/index.js b/samples/server/petstore/nodejs-express-server/controllers/index.js index 9e7194fff7ef..3dc796c1e507 100644 --- a/samples/server/petstore/nodejs-express-server/controllers/index.js +++ b/samples/server/petstore/nodejs-express-server/controllers/index.js @@ -1,11 +1,11 @@ -const Pet = require('./Pet'); -const Store = require('./Store'); -const User = require('./User'); -const Test = require('./Test'); +const PetController = require('./PetController'); +const StoreController = require('./StoreController'); +const UserController = require('./UserController'); +const TestController = require('./TestController'); module.exports = { - Pet, - Store, - User, - Test, + PetController, + StoreController, + UserController, + TestController, }; diff --git a/samples/server/petstore/nodejs-express-server/package.json b/samples/server/petstore/nodejs-express-server/package.json index 552051dca4d0..18e7d92069f9 100644 --- a/samples/server/petstore/nodejs-express-server/package.json +++ b/samples/server/petstore/nodejs-express-server/package.json @@ -8,7 +8,7 @@ "start": "node index.js" }, "keywords": [ - "openapi-tools" + "openapi-generator", "openapi" ], "license": "Unlicense", "private": true, diff --git a/samples/server/petstore/nodejs-express-server/service/PetService.js b/samples/server/petstore/nodejs-express-server/service/PetService.js index 0d8fc96248a0..d27433b78fab 100644 --- a/samples/server/petstore/nodejs-express-server/service/PetService.js +++ b/samples/server/petstore/nodejs-express-server/service/PetService.js @@ -2,16 +2,18 @@ const Service = require('./Service'); class PetService { + /** - * Add a new pet to the store - * @param body - * @returns {Promise} - */ - static addPet({ body }) { + * Add a new pet to the store + * + * body Pet Pet object that needs to be added to the store + * no response value expected for this operation + **/ + static.addPet({ body }) { return new Promise( async (resolve) => { try { - resolve(Service.successResponse(body)); + resolve(Service.successResponse('')); } catch (e) { resolve(Service.rejectResponse( e.message || 'Invalid input', @@ -22,15 +24,22 @@ class PetService { ); } - static updatePet({ body }) { + /** + * Deletes a pet + * + * petId Long Pet id to delete + * apiUnderscorekey String (optional) + * no response value expected for this operation + **/ + static.deletePet({ petId,apiUnderscorekey }) { return new Promise( async (resolve) => { try { - resolve(Service.successResponse(body)); + resolve(Service.successResponse('')); } catch (e) { resolve(Service.rejectResponse( - 'Invalid ID supplied', - 400, + e.message || 'Invalid input', + e.status || 405, )); } }, @@ -38,209 +47,138 @@ class PetService { } /** + * Finds Pets by status * Multiple status values can be provided with comma separated strings - * @param status - * @returns {Promise} - */ - static findPetsByStatus({ status }) { + * + * status List Status values that need to be considered for filter + * returns List + **/ + static.findPetsByStatus({ status }) { return new Promise( async (resolve) => { try { - resolve([ - { - photoUrls: ['photoUrls_1', 'photoUrls_2'], - name: 'dog_0', - id: 0, - category: { - name: 'category', - id: 1, - }, - tags: [{ - name: 'tag_1', - id: 1, - }, { - name: 'tag_2', - id: 2, - }], - status: 'available', - }, - { - photoUrls: ['photoUrls_1', 'photoUrls_2'], - name: 'dog_1', - id: 1, - category: { - name: 'category', - id: 1, - }, - tags: [{ - name: 'tags_1', - id: 1, - }, { - name: 'tags_2', - id: 2, - }], - status: 'available', - }], 200); + resolve(Service.successResponse('')); } catch (e) { - resolve( - Service.rejectResponse( - e.getMessage() || 'Invalid status value', - 400, - ), - ); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } /** - * Multiple tags can be provided with comma separated strings. Use - tag1, tag2, tag3 for testing. - * @param tags - * @returns {Promise} - */ - static findPetsByTags({ tags }) { + * Finds Pets by tags + * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. + * + * tags List Tags to filter by + * returns List + **/ + static.findPetsByTags({ tags }) { return new Promise( async (resolve) => { try { - resolve(Service.successResponse( - [ - { - photoUrls: ['photoUrls_1', 'photoUrls_2'], - name: 'dog_0', - id: 0, - category: { - name: 'category', - id: 1, - }, - tags: [{ - name: 'tag_1', - id: 1, - }, { - name: 'tag_2', - id: 2, - }], - status: 'available', - }, - { - photoUrls: ['photoUrls_1', 'photoUrls_2'], - name: 'dog_1', - id: 1, - category: { - name: 'category', - id: 1, - }, - tags: [{ - name: 'tags_1', - id: 1, - }, { - name: 'tags_2', - id: 2, - }], - status: 'available', - }, - ], 200, - )); + resolve(Service.successResponse('')); } catch (e) { - resolve( - Service.rejectResponse( - 'Invalid tag value', - 400, - ), - ); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } - static deletePet({ apiKey, petId }) { + /** + * Find pet by ID + * Returns a single pet + * + * petId Long ID of pet to return + * returns Pet + **/ + static.getPetById({ petId }) { return new Promise( async (resolve) => { try { - resolve(Service.successResponse(`success. apiKey ${apiKey}, petId: ${petId}`)); - } catch (err) { - resolve(Service.rejectResponse('Invalid pet value', 400)); + resolve(Service.successResponse('')); + } catch (e) { + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } - /** - * Returns a single pet - * @param petId - * @returns {Promise} - */ - static getPetById({ petId }) { + * Update an existing pet + * + * body Pet Pet object that needs to be added to the store + * no response value expected for this operation + **/ + static.updatePet({ body }) { return new Promise( async (resolve) => { try { - resolve({ - photoUrls: ['photoUrls_1', 'photoUrls_2'], - name: 'dog_0', - id: 0, - category: { - name: 'category', - id: 1, - }, - tags: [{ - name: 'tag_1', - id: 1, - }, { - name: 'tag_2', - id: 2, - }], - status: 'available', - }, 200); + resolve(Service.successResponse('')); } catch (e) { - resolve(Service.rejectResponse(e.getMessage() || 'Invalid ID supplied', 400)); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } /** + * Updates a pet in the store with form data * - * @param petId -- ID of pet that needs to be updated -- required - * @param body - * @returns {Promise} - */ - static updatePetWithForm({ petId, body }) { + * petId Long ID of pet that needs to be updated + * name String Updated name of the pet (optional) + * status String Updated status of the pet (optional) + * no response value expected for this operation + **/ + static.updatePetWithForm({ petId,name,status }) { return new Promise( - (resolve) => { + async (resolve) => { try { resolve(Service.successResponse('')); } catch (e) { - resolve(Service.rejectResponse('Invalid input', 405)); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } /** + * uploads an image * - * @param petId -- ID of pet to update - * @param body -- additionalMetadata, file - * @returns {Promise} - */ - static uploadFile({ petId, body }) { + * petId Long ID of pet to update + * additionalMetadata String Additional data to pass to server (optional) + * file File file to upload (optional) + * returns ApiResponse + **/ + static.uploadFile({ petId,additionalMetadata,file }) { return new Promise( async (resolve) => { try { - resolve(Service.successResponse( - { - code: 0, - type: 'type', - message: 'message', - }, - 200, - )); + resolve(Service.successResponse('')); } catch (e) { - resolve(Service.rejectResponse('')); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } + } module.exports = PetService; diff --git a/samples/server/petstore/nodejs-express-server/service/StoreService.js b/samples/server/petstore/nodejs-express-server/service/StoreService.js index afdbe501622d..ba0d3279ba72 100644 --- a/samples/server/petstore/nodejs-express-server/service/StoreService.js +++ b/samples/server/petstore/nodejs-express-server/service/StoreService.js @@ -1,87 +1,94 @@ -'use strict'; +/* eslint-disable no-unused-vars */ +const Service = require('./Service'); +class StoreService { -/** - * Delete purchase order by ID - * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - * - * orderId String ID of the order that needs to be deleted - * no response value expected for this operation - **/ -exports.deleteOrder = function(orderId) { - return new Promise(function(resolve, reject) { - resolve(); - }); -} - + /** + * Delete purchase order by ID + * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + * + * orderId String ID of the order that needs to be deleted + * no response value expected for this operation + **/ + static.deleteOrder({ orderId }) { + return new Promise( + async (resolve) => { + try { + resolve(Service.successResponse('')); + } catch (e) { + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } -/** - * Returns pet inventories by status - * Returns a map of status codes to quantities - * - * returns Map - **/ -exports.getInventory = function() { - return new Promise(function(resolve, reject) { - var examples = {}; - if (Object.keys(examples).length > 0) { - resolve(examples[Object.keys(examples)[0]]); - } else { - resolve(); - } - }); -} + /** + * Returns pet inventories by status + * Returns a map of status codes to quantities + * + * returns Map + **/ + static.getInventory({ }) { + return new Promise( + async (resolve) => { + try { + resolve(Service.successResponse('')); + } catch (e) { + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } + /** + * Find purchase order by ID + * For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions + * + * orderId Long ID of pet that needs to be fetched + * returns Order + **/ + static.getOrderById({ orderId }) { + return new Promise( + async (resolve) => { + try { + resolve(Service.successResponse('')); + } catch (e) { + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } -/** - * Find purchase order by ID - * For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions - * - * orderId Long ID of pet that needs to be fetched - * returns Order - **/ -exports.getOrderById = function(orderId) { - return new Promise(function(resolve, reject) { - var examples = {}; - examples['application/json'] = { - "petId" : 6, - "quantity" : 1, - "id" : 0, - "shipDate" : "2000-01-23T04:56:07.000+00:00", - "complete" : false, - "status" : "placed" -}; - if (Object.keys(examples).length > 0) { - resolve(examples[Object.keys(examples)[0]]); - } else { - resolve(); - } - }); -} - + /** + * Place an order for a pet + * + * body Order order placed for purchasing the pet + * returns Order + **/ + static.placeOrder({ body }) { + return new Promise( + async (resolve) => { + try { + resolve(Service.successResponse('')); + } catch (e) { + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } -/** - * Place an order for a pet - * - * body Order order placed for purchasing the pet - * returns Order - **/ -exports.placeOrder = function(body) { - return new Promise(function(resolve, reject) { - var examples = {}; - examples['application/json'] = { - "petId" : 6, - "quantity" : 1, - "id" : 0, - "shipDate" : "2000-01-23T04:56:07.000+00:00", - "complete" : false, - "status" : "placed" -}; - if (Object.keys(examples).length > 0) { - resolve(examples[Object.keys(examples)[0]]); - } else { - resolve(); - } - }); } +module.exports = StoreService; diff --git a/samples/server/petstore/nodejs-express-server/service/UserService.js b/samples/server/petstore/nodejs-express-server/service/UserService.js index c7d44234e61c..a4f1fcebe54b 100644 --- a/samples/server/petstore/nodejs-express-server/service/UserService.js +++ b/samples/server/petstore/nodejs-express-server/service/UserService.js @@ -1,85 +1,180 @@ +/* eslint-disable no-unused-vars */ const Service = require('./Service'); class UserService { - static loginUser({ username, password }) { + + /** + * Create user + * This can only be done by the logged in user. + * + * body User Created user object + * no response value expected for this operation + **/ + static.createUser({ body }) { return new Promise( async (resolve) => { try { - if (username !== undefined && password !== undefined) { - resolve(Service.successResponse({ string: 'String' })); - } else { - resolve(Service.rejectResponse('Wrong username/password', 400)); - } + resolve(Service.successResponse('')); } catch (e) { - resolve(Service.rejectResponse(e.message)); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } - static logoutUser() { + /** + * Creates list of users with given input array + * + * body List List of user object + * no response value expected for this operation + **/ + static.createUsersWithArrayInput({ body }) { return new Promise( - (resolve) => { + async (resolve) => { try { - resolve(Service.successResponse('logout user')); + resolve(Service.successResponse('')); } catch (e) { - resolve(Service.rejectResponse(e.message)); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } - static deleteUser({ username }) { + /** + * Creates list of users with given input array + * + * body List List of user object + * no response value expected for this operation + **/ + static.createUsersWithListInput({ body }) { return new Promise( - (resolve) => { + async (resolve) => { try { - if (username !== undefined) { - resolve(Service.successResponse('deleteUser')); - } else { - resolve(Service.rejectResponse('Invalid username supplied', 400)); - } + resolve(Service.successResponse('')); } catch (e) { - resolve(Service.rejectResponse(e.message)); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } - static getUserByName({ username }) { + /** + * Delete user + * This can only be done by the logged in user. + * + * username String The name that needs to be deleted + * no response value expected for this operation + **/ + static.deleteUser({ username }) { return new Promise( - (resolve) => { + async (resolve) => { try { - resolve(Service.successResponse({ - id: 1, - username, - firstName: 'firstName', - lastName: 'lastName', - email: 'email', - phone: '213-456-7890', - userStatus: 1, - })); + resolve(Service.successResponse('')); } catch (e) { - resolve(Service.rejectResponse(e.message)); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } - static updateUser({ username, user }) { + /** + * Get user by user name + * + * username String The name that needs to be fetched. Use user1 for testing. + * returns User + **/ + static.getUserByName({ username }) { return new Promise( - (resolve) => { + async (resolve) => { try { - if (user.username === username) { - resolve(Service.successResponse(user)); - } else { - resolve(Service.successResponse({})); - } + resolve(Service.successResponse('')); } catch (e) { - resolve(Service.rejectResponse(e.message)); + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); } }, ); } + + /** + * Logs user into the system + * + * username String The user name for login + * password String The password for login in clear text + * returns String + **/ + static.loginUser({ username,password }) { + return new Promise( + async (resolve) => { + try { + resolve(Service.successResponse('')); + } catch (e) { + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } + + /** + * Logs out current logged in user session + * + * no response value expected for this operation + **/ + static.logoutUser({ }) { + return new Promise( + async (resolve) => { + try { + resolve(Service.successResponse('')); + } catch (e) { + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } + + /** + * Updated user + * This can only be done by the logged in user. + * + * username String name that need to be deleted + * body User Updated user object + * no response value expected for this operation + **/ + static.updateUser({ username,body }) { + return new Promise( + async (resolve) => { + try { + resolve(Service.successResponse('')); + } catch (e) { + resolve(Service.rejectResponse( + e.message || 'Invalid input', + e.status || 405, + )); + } + }, + ); + } + } module.exports = UserService; diff --git a/samples/server/petstore/nodejs-express-server/service/index.js b/samples/server/petstore/nodejs-express-server/service/index.js index 20fb92f70848..ca9599851baf 100644 --- a/samples/server/petstore/nodejs-express-server/service/index.js +++ b/samples/server/petstore/nodejs-express-server/service/index.js @@ -1,11 +1,11 @@ const PetService = require('./PetService'); const StoreService = require('./StoreService'); const UserService = require('./UserService'); -// const TestService = require('./TestService'); +const TestService = require('./TestService'); module.exports = { PetService, StoreService, UserService, - // TestService, + TestService, };