diff --git a/bin/nodejs-petstore-google-cloud-functions.sh b/bin/nodejs-petstore-google-cloud-functions.sh new file mode 100755 index 00000000000..f5df577b481 --- /dev/null +++ b/bin/nodejs-petstore-google-cloud-functions.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +SCRIPT="$0" + +while [ -h "$SCRIPT" ] ; do + ls=`ls -ld "$SCRIPT"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=`dirname "$SCRIPT"`/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=`dirname "$SCRIPT"`/.. + APP_DIR=`cd "${APP_DIR}"; pwd` +fi + +executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -i modules/swagger-codegen/src/test/resources/2_0/petstore.yaml -l nodejs-server --additional-properties=googleCloudFunctions=true -o samples/server/petstore/nodejs-google-cloud-functions" + +java $JAVA_OPTS -Dservice -jar $executable $ags diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java index b9ab1b00f8b..87e44d23632 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NodeJSServerCodegen.java @@ -24,10 +24,16 @@ public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig private static final Logger LOGGER = LoggerFactory.getLogger(NodeJSServerCodegen.class); + public static final String GOOGLE_CLOUD_FUNCTIONS = "googleCloudFunctions"; + public static final String EXPORTED_NAME = "exportedName"; + protected String apiVersion = "1.0.0"; protected int serverPort = 8080; protected String projectName = "swagger-server"; + protected boolean googleCloudFunctions; + protected String exportedName; + public NodeJSServerCodegen() { super(); @@ -76,27 +82,15 @@ public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig additionalProperties.put("apiVersion", apiVersion); additionalProperties.put("serverPort", serverPort); - /* - * 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("swagger.mustache", - "api", - "swagger.yaml") - ); - 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 (System.getProperty("noservice") == null) { - apiTemplateFiles.put( - "service.mustache", // the template to use - "Service.js"); // the extension for each file to write - } + 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.")); } @Override @@ -171,6 +165,22 @@ public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig 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 postProcessOperations(Map objs) { @SuppressWarnings("unchecked") @@ -240,6 +250,46 @@ public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig return opsByPathList; } + @Override + public void processOpts() { + super.processOpts(); + + 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("swagger.mustache", + "api", + "swagger.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 (System.getProperty("noservice") == null) { + apiTemplateFiles.put( + "service.mustache", // the template to use + "Service.js"); // the extension for each file to write + } + } + @Override public void preprocessSwagger(Swagger swagger) { String host = swagger.getHost(); @@ -262,6 +312,22 @@ public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig } } + 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)) { + String basePath = swagger.getBasePath(); + 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 Map paths = swagger.getPaths(); if(paths != null) { diff --git a/modules/swagger-codegen/src/main/resources/nodejs-google-cloud-functions/index.mustache b/modules/swagger-codegen/src/main/resources/nodejs-google-cloud-functions/index.mustache new file mode 100644 index 00000000000..b406ff7f140 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nodejs-google-cloud-functions/index.mustache @@ -0,0 +1,44 @@ +'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/swagger.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/swagger-codegen/src/main/resources/nodejs/README.mustache b/modules/swagger-codegen/src/main/resources/nodejs/README.mustache index b8fd4cd80ab..b7df8abcd3e 100644 --- a/modules/swagger-codegen/src/main/resources/nodejs/README.mustache +++ b/modules/swagger-codegen/src/main/resources/nodejs/README.mustache @@ -3,6 +3,7 @@ ## Overview This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) 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: @@ -15,5 +16,12 @@ 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. diff --git a/modules/swagger-codegen/src/main/resources/nodejs/index-gcf.mustache b/modules/swagger-codegen/src/main/resources/nodejs/index-gcf.mustache new file mode 100644 index 00000000000..b406ff7f140 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nodejs/index-gcf.mustache @@ -0,0 +1,44 @@ +'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/swagger.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/swagger-codegen/src/main/resources/nodejs/package.mustache b/modules/swagger-codegen/src/main/resources/nodejs/package.mustache index 4e59cfb3c2a..ed296f865c2 100644 --- a/modules/swagger-codegen/src/main/resources/nodejs/package.mustache +++ b/modules/swagger-codegen/src/main/resources/nodejs/package.mustache @@ -3,17 +3,21 @@ "version": "{{appVersion}}", "description": "{{{appDescription}}}", "main": "index.js", + {{^googleCloudFunctions}} "scripts": { "prestart": "npm install", "start": "node index.js" - }, + }, + {{/googleCloudFunctions}} "keywords": [ "swagger" ], "license": "Unlicense", "private": true, "dependencies": { + {{^googleCloudFunctions}} "connect": "^3.2.0", + {{/googleCloudFunctions}} "js-yaml": "^3.3.0", "swagger-tools": "0.10.1" } diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/nodejs/NodeJSServerOptionsTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/nodejs/NodeJSServerOptionsTest.java index c1cfa43b08b..a1cc4aab2b9 100644 --- a/modules/swagger-codegen/src/test/java/io/swagger/codegen/nodejs/NodeJSServerOptionsTest.java +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/nodejs/NodeJSServerOptionsTest.java @@ -27,6 +27,8 @@ public class NodeJSServerOptionsTest extends AbstractOptionsTest { protected void setExpectations() { new Expectations(clientCodegen) {{ clientCodegen.setSortParamsByRequiredFlag(Boolean.valueOf(NodeJSServerOptionsProvider.SORT_PARAMS_VALUE)); + clientCodegen.setGoogleCloudFunctions(Boolean.valueOf(NodeJSServerOptionsProvider.GOOGLE_CLOUD_FUNCTIONS)); + clientCodegen.setExportedName(NodeJSServerOptionsProvider.EXPORTED_NAME); times = 1; }}; } diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NodeJSServerOptionsProvider.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NodeJSServerOptionsProvider.java index 6252bbd08fc..e18704e2b54 100644 --- a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NodeJSServerOptionsProvider.java +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NodeJSServerOptionsProvider.java @@ -1,7 +1,7 @@ package io.swagger.codegen.options; import io.swagger.codegen.CodegenConstants; - +import io.swagger.codegen.languages.NodeJSServerCodegen; import com.google.common.collect.ImmutableMap; import java.util.Map; @@ -9,6 +9,8 @@ import java.util.Map; public class NodeJSServerOptionsProvider implements OptionsProvider { public static final String SORT_PARAMS_VALUE = "false"; public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true"; + public static final String GOOGLE_CLOUD_FUNCTIONS = "false"; + public static final String EXPORTED_NAME = "exported"; @Override public String getLanguage() { @@ -20,6 +22,8 @@ public class NodeJSServerOptionsProvider implements OptionsProvider { ImmutableMap.Builder builder = new ImmutableMap.Builder(); return builder.put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_VALUE) .put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE) + .put(NodeJSServerCodegen.GOOGLE_CLOUD_FUNCTIONS, GOOGLE_CLOUD_FUNCTIONS) + .put(NodeJSServerCodegen.EXPORTED_NAME, EXPORTED_NAME) .build(); } diff --git a/samples/server/petstore/nodejs-google-cloud-functions/README.md b/samples/server/petstore/nodejs-google-cloud-functions/README.md new file mode 100644 index 00000000000..44270f0a198 --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/README.md @@ -0,0 +1,11 @@ +# Swagger generated server + +## Overview +This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. + +### 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. + +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-google-cloud-functions/api/swagger.yaml b/samples/server/petstore/nodejs-google-cloud-functions/api/swagger.yaml new file mode 100644 index 00000000000..b47e700ae1f --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/api/swagger.yaml @@ -0,0 +1,734 @@ +--- +swagger: "2.0" +info: + description: "This is a sample server Petstore server. You can find out more about\ + \ Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).\ + \ For this sample, you can use the api key `special-key` to test the authorization\ + \ filters." + version: "1.0.0" + title: "Swagger Petstore" + termsOfService: "http://swagger.io/terms/" + contact: + email: "apiteam@swagger.io" + license: + name: "Apache 2.0" + url: "http://www.apache.org/licenses/LICENSE-2.0.html" +host: "petstore.swagger.io" +basePath: "/v2" +tags: +- name: "pet" + description: "Everything about your Pets" + externalDocs: + description: "Find out more" + url: "http://swagger.io" +- name: "store" + description: "Access to Petstore orders" +- name: "user" + description: "Operations about user" + externalDocs: + description: "Find out more about our store" + url: "http://swagger.io" +schemes: +- "http" +paths: + /pet: + post: + tags: + - "pet" + summary: "Add a new pet to the store" + description: "" + operationId: "addPet" + consumes: + - "application/json" + - "application/xml" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "Pet object that needs to be added to the store" + required: true + schema: + $ref: "#/definitions/Pet" + responses: + 405: + description: "Invalid input" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + x-swagger-router-controller: "Pet" + put: + tags: + - "pet" + summary: "Update an existing pet" + description: "" + operationId: "updatePet" + consumes: + - "application/json" + - "application/xml" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "Pet object that needs to be added to the store" + required: true + schema: + $ref: "#/definitions/Pet" + responses: + 400: + description: "Invalid ID supplied" + 404: + description: "Pet not found" + 405: + description: "Validation exception" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + x-swagger-router-controller: "Pet" + /pet/findByStatus: + get: + tags: + - "pet" + summary: "Finds Pets by status" + description: "Multiple status values can be provided with comma separated strings" + operationId: "findPetsByStatus" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "status" + in: "query" + description: "Status values that need to be considered for filter" + required: true + type: "array" + items: + type: "string" + default: "available" + enum: + - "available" + - "pending" + - "sold" + collectionFormat: "csv" + responses: + 200: + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/Pet" + 400: + description: "Invalid status value" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + x-swagger-router-controller: "Pet" + /pet/findByTags: + get: + tags: + - "pet" + summary: "Finds Pets by tags" + description: "Multiple tags can be provided with comma separated strings. Use\ + \ tag1, tag2, tag3 for testing." + operationId: "findPetsByTags" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "tags" + in: "query" + description: "Tags to filter by" + required: true + type: "array" + items: + type: "string" + collectionFormat: "csv" + responses: + 200: + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/Pet" + 400: + description: "Invalid tag value" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + x-swagger-router-controller: "Pet" + /pet/{petId}: + get: + tags: + - "pet" + summary: "Find pet by ID" + description: "Returns a single pet" + operationId: "getPetById" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "petId" + in: "path" + description: "ID of pet to return" + required: true + type: "integer" + format: "int64" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Pet" + 400: + description: "Invalid ID supplied" + 404: + description: "Pet not found" + security: + - api_key: [] + x-swagger-router-controller: "Pet" + post: + tags: + - "pet" + summary: "Updates a pet in the store with form data" + description: "" + operationId: "updatePetWithForm" + consumes: + - "application/x-www-form-urlencoded" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "petId" + in: "path" + description: "ID of pet that needs to be updated" + required: true + type: "integer" + format: "int64" + - name: "name" + in: "formData" + description: "Updated name of the pet" + required: false + type: "string" + - name: "status" + in: "formData" + description: "Updated status of the pet" + required: false + type: "string" + responses: + 405: + description: "Invalid input" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + x-swagger-router-controller: "Pet" + delete: + tags: + - "pet" + summary: "Deletes a pet" + description: "" + operationId: "deletePet" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "api_key" + in: "header" + required: false + type: "string" + - name: "petId" + in: "path" + description: "Pet id to delete" + required: true + type: "integer" + format: "int64" + responses: + 400: + description: "Invalid pet value" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + x-swagger-router-controller: "Pet" + /pet/{petId}/uploadImage: + post: + tags: + - "pet" + summary: "uploads an image" + description: "" + operationId: "uploadFile" + consumes: + - "multipart/form-data" + produces: + - "application/json" + parameters: + - name: "petId" + in: "path" + description: "ID of pet to update" + required: true + type: "integer" + format: "int64" + - name: "additionalMetadata" + in: "formData" + description: "Additional data to pass to server" + required: false + type: "string" + - name: "file" + in: "formData" + description: "file to upload" + required: false + type: "file" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/ApiResponse" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + x-swagger-router-controller: "Pet" + /store/inventory: + get: + tags: + - "store" + summary: "Returns pet inventories by status" + description: "Returns a map of status codes to quantities" + operationId: "getInventory" + produces: + - "application/json" + parameters: [] + responses: + 200: + description: "successful operation" + schema: + type: "object" + additionalProperties: + type: "integer" + format: "int32" + security: + - api_key: [] + x-swagger-router-controller: "Store" + /store/order: + post: + tags: + - "store" + summary: "Place an order for a pet" + description: "" + operationId: "placeOrder" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "order placed for purchasing the pet" + required: true + schema: + $ref: "#/definitions/Order" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Order" + 400: + description: "Invalid Order" + x-swagger-router-controller: "Store" + /store/order/{orderId}: + get: + tags: + - "store" + summary: "Find purchase order by ID" + description: "For valid response try integer IDs with value <= 5 or > 10. Other\ + \ values will generated exceptions" + operationId: "getOrderById" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "orderId" + in: "path" + description: "ID of pet that needs to be fetched" + required: true + type: "integer" + maximum: 5 + minimum: 1 + format: "int64" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Order" + 400: + description: "Invalid ID supplied" + 404: + description: "Order not found" + x-swagger-router-controller: "Store" + delete: + tags: + - "store" + summary: "Delete purchase order by ID" + description: "For valid response try integer IDs with value < 1000. Anything\ + \ above 1000 or nonintegers will generate API errors" + operationId: "deleteOrder" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "orderId" + in: "path" + description: "ID of the order that needs to be deleted" + required: true + type: "string" + minimum: 1 + responses: + 400: + description: "Invalid ID supplied" + 404: + description: "Order not found" + x-swagger-router-controller: "Store" + /user: + post: + tags: + - "user" + summary: "Create user" + description: "This can only be done by the logged in user." + operationId: "createUser" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "Created user object" + required: true + schema: + $ref: "#/definitions/User" + responses: + default: + description: "successful operation" + x-swagger-router-controller: "User" + /user/createWithArray: + post: + tags: + - "user" + summary: "Creates list of users with given input array" + description: "" + operationId: "createUsersWithArrayInput" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "List of user object" + required: true + schema: + type: "array" + items: + $ref: "#/definitions/User" + responses: + default: + description: "successful operation" + x-swagger-router-controller: "User" + /user/createWithList: + post: + tags: + - "user" + summary: "Creates list of users with given input array" + description: "" + operationId: "createUsersWithListInput" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "List of user object" + required: true + schema: + type: "array" + items: + $ref: "#/definitions/User" + responses: + default: + description: "successful operation" + x-swagger-router-controller: "User" + /user/login: + get: + tags: + - "user" + summary: "Logs user into the system" + description: "" + operationId: "loginUser" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "username" + in: "query" + description: "The user name for login" + required: true + type: "string" + - name: "password" + in: "query" + description: "The password for login in clear text" + required: true + type: "string" + responses: + 200: + description: "successful operation" + schema: + type: "string" + headers: + X-Rate-Limit: + type: "integer" + format: "int32" + description: "calls per hour allowed by the user" + X-Expires-After: + type: "string" + format: "date-time" + description: "date in UTC when toekn expires" + 400: + description: "Invalid username/password supplied" + x-swagger-router-controller: "User" + /user/logout: + get: + tags: + - "user" + summary: "Logs out current logged in user session" + description: "" + operationId: "logoutUser" + produces: + - "application/xml" + - "application/json" + parameters: [] + responses: + default: + description: "successful operation" + x-swagger-router-controller: "User" + /user/{username}: + get: + tags: + - "user" + summary: "Get user by user name" + description: "" + operationId: "getUserByName" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "username" + in: "path" + description: "The name that needs to be fetched. Use user1 for testing. " + required: true + type: "string" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/User" + 400: + description: "Invalid username supplied" + 404: + description: "User not found" + x-swagger-router-controller: "User" + put: + tags: + - "user" + summary: "Updated user" + description: "This can only be done by the logged in user." + operationId: "updateUser" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "username" + in: "path" + description: "name that need to be deleted" + required: true + type: "string" + - in: "body" + name: "body" + description: "Updated user object" + required: true + schema: + $ref: "#/definitions/User" + responses: + 400: + description: "Invalid user supplied" + 404: + description: "User not found" + x-swagger-router-controller: "User" + delete: + tags: + - "user" + summary: "Delete user" + description: "This can only be done by the logged in user." + operationId: "deleteUser" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "username" + in: "path" + description: "The name that needs to be deleted" + required: true + type: "string" + responses: + 400: + description: "Invalid username supplied" + 404: + description: "User not found" + x-swagger-router-controller: "User" +securityDefinitions: + petstore_auth: + type: "oauth2" + authorizationUrl: "http://petstore.swagger.io/api/oauth/dialog" + flow: "implicit" + scopes: + write:pets: "modify pets in your account" + read:pets: "read your pets" + api_key: + type: "apiKey" + name: "api_key" + in: "header" +definitions: + Order: + type: "object" + properties: + id: + type: "integer" + format: "int64" + petId: + type: "integer" + format: "int64" + quantity: + type: "integer" + format: "int32" + shipDate: + type: "string" + format: "date-time" + status: + type: "string" + description: "Order Status" + enum: + - "placed" + - "approved" + - "delivered" + complete: + type: "boolean" + default: false + title: "Pet Order" + description: "An order for a pets from the pet store" + xml: + name: "Order" + Category: + type: "object" + properties: + id: + type: "integer" + format: "int64" + name: + type: "string" + title: "Pet catehgry" + description: "A category for a pet" + xml: + name: "Category" + User: + type: "object" + properties: + id: + type: "integer" + format: "int64" + username: + type: "string" + firstName: + type: "string" + lastName: + type: "string" + email: + type: "string" + password: + type: "string" + phone: + type: "string" + userStatus: + type: "integer" + format: "int32" + description: "User Status" + title: "a User" + description: "A User who is purchasing from the pet store" + xml: + name: "User" + Tag: + type: "object" + properties: + id: + type: "integer" + format: "int64" + name: + type: "string" + title: "Pet Tag" + description: "A tag for a pet" + xml: + name: "Tag" + Pet: + type: "object" + required: + - "name" + - "photoUrls" + properties: + id: + type: "integer" + format: "int64" + category: + $ref: "#/definitions/Category" + name: + type: "string" + example: "doggie" + photoUrls: + type: "array" + xml: + name: "photoUrl" + wrapped: true + items: + type: "string" + tags: + type: "array" + xml: + name: "tag" + wrapped: true + items: + $ref: "#/definitions/Tag" + status: + type: "string" + description: "pet status in the store" + enum: + - "available" + - "pending" + - "sold" + title: "a Pet" + description: "A pet for sale in the pet store" + xml: + name: "Pet" + ApiResponse: + type: "object" + properties: + code: + type: "integer" + format: "int32" + type: + type: "string" + message: + type: "string" + title: "An uploaded response" + description: "Describes the result of uploading an image resource" +externalDocs: + description: "Find out more about Swagger" + url: "http://swagger.io" diff --git a/samples/server/petstore/nodejs-google-cloud-functions/controllers/Pet.js b/samples/server/petstore/nodejs-google-cloud-functions/controllers/Pet.js new file mode 100644 index 00000000000..3748305bfbe --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/controllers/Pet.js @@ -0,0 +1,39 @@ +'use strict'; + +var url = require('url'); + + +var Pet = require('./PetService'); + + +module.exports.addPet = function addPet (req, res, next) { + Pet.addPet(req.swagger.params, res, next); +}; + +module.exports.deletePet = function deletePet (req, res, next) { + Pet.deletePet(req.swagger.params, res, next); +}; + +module.exports.findPetsByStatus = function findPetsByStatus (req, res, next) { + Pet.findPetsByStatus(req.swagger.params, res, next); +}; + +module.exports.findPetsByTags = function findPetsByTags (req, res, next) { + Pet.findPetsByTags(req.swagger.params, res, next); +}; + +module.exports.getPetById = function getPetById (req, res, next) { + Pet.getPetById(req.swagger.params, res, next); +}; + +module.exports.updatePet = function updatePet (req, res, next) { + Pet.updatePet(req.swagger.params, res, next); +}; + +module.exports.updatePetWithForm = function updatePetWithForm (req, res, next) { + Pet.updatePetWithForm(req.swagger.params, res, next); +}; + +module.exports.uploadFile = function uploadFile (req, res, next) { + Pet.uploadFile(req.swagger.params, res, next); +}; diff --git a/samples/server/petstore/nodejs-google-cloud-functions/controllers/PetService.js b/samples/server/petstore/nodejs-google-cloud-functions/controllers/PetService.js new file mode 100644 index 00000000000..c8da68c1519 --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/controllers/PetService.js @@ -0,0 +1,154 @@ +'use strict'; + +exports.addPet = function(args, res, next) { + /** + * parameters expected in the args: + * body (Pet) + **/ + // no response value expected for this operation + res.end(); +} + +exports.deletePet = function(args, res, next) { + /** + * parameters expected in the args: + * petId (Long) + * api_key (String) + **/ + // no response value expected for this operation + res.end(); +} + +exports.findPetsByStatus = function(args, res, next) { + /** + * parameters expected in the args: + * status (List) + **/ + var examples = {}; + examples['application/json'] = [ { + "photoUrls" : [ "aeiou" ], + "name" : "doggie", + "id" : 123456789, + "category" : { + "name" : "aeiou", + "id" : 123456789 + }, + "tags" : [ { + "name" : "aeiou", + "id" : 123456789 + } ], + "status" : "aeiou" +} ]; + if(Object.keys(examples).length > 0) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2)); + } + else { + res.end(); + } + +} + +exports.findPetsByTags = function(args, res, next) { + /** + * parameters expected in the args: + * tags (List) + **/ + var examples = {}; + examples['application/json'] = [ { + "photoUrls" : [ "aeiou" ], + "name" : "doggie", + "id" : 123456789, + "category" : { + "name" : "aeiou", + "id" : 123456789 + }, + "tags" : [ { + "name" : "aeiou", + "id" : 123456789 + } ], + "status" : "aeiou" +} ]; + if(Object.keys(examples).length > 0) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2)); + } + else { + res.end(); + } + +} + +exports.getPetById = function(args, res, next) { + /** + * parameters expected in the args: + * petId (Long) + **/ + var examples = {}; + examples['application/json'] = { + "photoUrls" : [ "aeiou" ], + "name" : "doggie", + "id" : 123456789, + "category" : { + "name" : "aeiou", + "id" : 123456789 + }, + "tags" : [ { + "name" : "aeiou", + "id" : 123456789 + } ], + "status" : "aeiou" +}; + if(Object.keys(examples).length > 0) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2)); + } + else { + res.end(); + } + +} + +exports.updatePet = function(args, res, next) { + /** + * parameters expected in the args: + * body (Pet) + **/ + // no response value expected for this operation + res.end(); +} + +exports.updatePetWithForm = function(args, res, next) { + /** + * parameters expected in the args: + * petId (Long) + * name (String) + * status (String) + **/ + // no response value expected for this operation + res.end(); +} + +exports.uploadFile = function(args, res, next) { + /** + * parameters expected in the args: + * petId (Long) + * additionalMetadata (String) + * file (File) + **/ + var examples = {}; + examples['application/json'] = { + "code" : 123, + "type" : "aeiou", + "message" : "aeiou" +}; + if(Object.keys(examples).length > 0) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2)); + } + else { + res.end(); + } + +} + diff --git a/samples/server/petstore/nodejs-google-cloud-functions/controllers/Store.js b/samples/server/petstore/nodejs-google-cloud-functions/controllers/Store.js new file mode 100644 index 00000000000..ac67c740d29 --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/controllers/Store.js @@ -0,0 +1,23 @@ +'use strict'; + +var url = require('url'); + + +var Store = require('./StoreService'); + + +module.exports.deleteOrder = function deleteOrder (req, res, next) { + Store.deleteOrder(req.swagger.params, res, next); +}; + +module.exports.getInventory = function getInventory (req, res, next) { + Store.getInventory(req.swagger.params, res, next); +}; + +module.exports.getOrderById = function getOrderById (req, res, next) { + Store.getOrderById(req.swagger.params, res, next); +}; + +module.exports.placeOrder = function placeOrder (req, res, next) { + Store.placeOrder(req.swagger.params, res, next); +}; diff --git a/samples/server/petstore/nodejs-google-cloud-functions/controllers/StoreService.js b/samples/server/petstore/nodejs-google-cloud-functions/controllers/StoreService.js new file mode 100644 index 00000000000..aed5113a915 --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/controllers/StoreService.js @@ -0,0 +1,77 @@ +'use strict'; + +exports.deleteOrder = function(args, res, next) { + /** + * parameters expected in the args: + * orderId (String) + **/ + // no response value expected for this operation + res.end(); +} + +exports.getInventory = function(args, res, next) { + /** + * parameters expected in the args: + **/ + var examples = {}; + examples['application/json'] = { + "key" : 123 +}; + if(Object.keys(examples).length > 0) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2)); + } + else { + res.end(); + } + +} + +exports.getOrderById = function(args, res, next) { + /** + * parameters expected in the args: + * orderId (Long) + **/ + var examples = {}; + examples['application/json'] = { + "petId" : 123456789, + "quantity" : 123, + "id" : 123456789, + "shipDate" : "2000-01-23T04:56:07.000+00:00", + "complete" : true, + "status" : "aeiou" +}; + if(Object.keys(examples).length > 0) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2)); + } + else { + res.end(); + } + +} + +exports.placeOrder = function(args, res, next) { + /** + * parameters expected in the args: + * body (Order) + **/ + var examples = {}; + examples['application/json'] = { + "petId" : 123456789, + "quantity" : 123, + "id" : 123456789, + "shipDate" : "2000-01-23T04:56:07.000+00:00", + "complete" : true, + "status" : "aeiou" +}; + if(Object.keys(examples).length > 0) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2)); + } + else { + res.end(); + } + +} + diff --git a/samples/server/petstore/nodejs-google-cloud-functions/controllers/User.js b/samples/server/petstore/nodejs-google-cloud-functions/controllers/User.js new file mode 100644 index 00000000000..bac1d7f6a88 --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/controllers/User.js @@ -0,0 +1,39 @@ +'use strict'; + +var url = require('url'); + + +var User = require('./UserService'); + + +module.exports.createUser = function createUser (req, res, next) { + User.createUser(req.swagger.params, res, next); +}; + +module.exports.createUsersWithArrayInput = function createUsersWithArrayInput (req, res, next) { + User.createUsersWithArrayInput(req.swagger.params, res, next); +}; + +module.exports.createUsersWithListInput = function createUsersWithListInput (req, res, next) { + User.createUsersWithListInput(req.swagger.params, res, next); +}; + +module.exports.deleteUser = function deleteUser (req, res, next) { + User.deleteUser(req.swagger.params, res, next); +}; + +module.exports.getUserByName = function getUserByName (req, res, next) { + User.getUserByName(req.swagger.params, res, next); +}; + +module.exports.loginUser = function loginUser (req, res, next) { + User.loginUser(req.swagger.params, res, next); +}; + +module.exports.logoutUser = function logoutUser (req, res, next) { + User.logoutUser(req.swagger.params, res, next); +}; + +module.exports.updateUser = function updateUser (req, res, next) { + User.updateUser(req.swagger.params, res, next); +}; diff --git a/samples/server/petstore/nodejs-google-cloud-functions/controllers/UserService.js b/samples/server/petstore/nodejs-google-cloud-functions/controllers/UserService.js new file mode 100644 index 00000000000..3a62feeaf3f --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/controllers/UserService.js @@ -0,0 +1,100 @@ +'use strict'; + +exports.createUser = function(args, res, next) { + /** + * parameters expected in the args: + * body (User) + **/ + // no response value expected for this operation + res.end(); +} + +exports.createUsersWithArrayInput = function(args, res, next) { + /** + * parameters expected in the args: + * body (List) + **/ + // no response value expected for this operation + res.end(); +} + +exports.createUsersWithListInput = function(args, res, next) { + /** + * parameters expected in the args: + * body (List) + **/ + // no response value expected for this operation + res.end(); +} + +exports.deleteUser = function(args, res, next) { + /** + * parameters expected in the args: + * username (String) + **/ + // no response value expected for this operation + res.end(); +} + +exports.getUserByName = function(args, res, next) { + /** + * parameters expected in the args: + * username (String) + **/ + var examples = {}; + examples['application/json'] = { + "firstName" : "aeiou", + "lastName" : "aeiou", + "password" : "aeiou", + "userStatus" : 123, + "phone" : "aeiou", + "id" : 123456789, + "email" : "aeiou", + "username" : "aeiou" +}; + if(Object.keys(examples).length > 0) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2)); + } + else { + res.end(); + } + +} + +exports.loginUser = function(args, res, next) { + /** + * parameters expected in the args: + * username (String) + * password (String) + **/ + var examples = {}; + examples['application/json'] = "aeiou"; + if(Object.keys(examples).length > 0) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(examples[Object.keys(examples)[0]] || {}, null, 2)); + } + else { + res.end(); + } + +} + +exports.logoutUser = function(args, res, next) { + /** + * parameters expected in the args: + **/ + // no response value expected for this operation + res.end(); +} + +exports.updateUser = function(args, res, next) { + /** + * parameters expected in the args: + * username (String) + * body (User) + **/ + // no response value expected for this operation + res.end(); +} + diff --git a/samples/server/petstore/nodejs-google-cloud-functions/index.js b/samples/server/petstore/nodejs-google-cloud-functions/index.js new file mode 100644 index 00000000000..7c4cf42a3be --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/index.js @@ -0,0 +1,44 @@ +'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/swagger.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.v2 = 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/samples/server/petstore/nodejs-google-cloud-functions/package.json b/samples/server/petstore/nodejs-google-cloud-functions/package.json new file mode 100644 index 00000000000..5008aba1acd --- /dev/null +++ b/samples/server/petstore/nodejs-google-cloud-functions/package.json @@ -0,0 +1,15 @@ +{ + "name": "swagger-petstore", + "version": "1.0.0", + "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.", + "main": "index.js", + "keywords": [ + "swagger" + ], + "license": "Unlicense", + "private": true, + "dependencies": { + "js-yaml": "^3.3.0", + "swagger-tools": "0.10.1" + } +}