From 706086632822609896f16cb96cbeee5d63e64f9d Mon Sep 17 00:00:00 2001 From: Mauro Valota Date: Wed, 21 Jun 2023 15:55:40 +0200 Subject: [PATCH 01/20] First version of Zapier Generator --- bin/configs/zapier-petstore-new.yaml | 6 + .../languages/ZapierClientCodegen.java | 118 ++++++++++++++++++ .../org.openapitools.codegen.CodegenConfig | 1 + .../src/main/resources/zapier/README.mustache | 0 .../src/main/resources/zapier/api.mustache | 0 .../src/main/resources/zapier/model.mustache | 0 6 files changed, 125 insertions(+) create mode 100644 bin/configs/zapier-petstore-new.yaml create mode 100644 modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java create mode 100644 modules/openapi-generator/src/main/resources/zapier/README.mustache create mode 100644 modules/openapi-generator/src/main/resources/zapier/api.mustache create mode 100644 modules/openapi-generator/src/main/resources/zapier/model.mustache diff --git a/bin/configs/zapier-petstore-new.yaml b/bin/configs/zapier-petstore-new.yaml new file mode 100644 index 000000000000..37f67475ce91 --- /dev/null +++ b/bin/configs/zapier-petstore-new.yaml @@ -0,0 +1,6 @@ +generatorName: zapier +outputDir: samples/client/petstore/zapier +inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml +templateDir: modules/openapi-generator/src/main/resources/zapier +additionalProperties: + hideGenerationTimestamp: "true" diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java new file mode 100644 index 000000000000..c46dfc3af1a1 --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java @@ -0,0 +1,118 @@ +package org.openapitools.codegen.languages; + +import org.openapitools.codegen.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +import static org.openapitools.codegen.utils.StringUtils.escape; + +public class ZapierClientCodegen extends DefaultCodegen implements CodegenConfig { + public static final String PROJECT_NAME = "projectName"; + + private final Logger LOGGER = LoggerFactory.getLogger(ZapierClientCodegen.class); + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "zapier"; + } + + public String getHelp() { + return "Generates a zapier client."; + } + + public ZapierClientCodegen() { + super(); + + outputFolder = "generated-code" + File.separator + "zapier"; + modelTemplateFiles.put("model.mustache", ".zz"); + apiTemplateFiles.put("api.mustache", ".zz"); + embeddedTemplateDir = templateDir = "zapier"; + apiPackage = "Apis"; + modelPackage = "Models"; + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + + languageSpecificPrimitives.clear(); + languageSpecificPrimitives.add("ByteArray"); + languageSpecificPrimitives.add("DateTime"); + languageSpecificPrimitives.add("URI"); + languageSpecificPrimitives.add("UUID"); + languageSpecificPrimitives.add("boolean"); + languageSpecificPrimitives.add("char"); + languageSpecificPrimitives.add("date"); + languageSpecificPrimitives.add("decimal"); + languageSpecificPrimitives.add("double"); + languageSpecificPrimitives.add("file"); + languageSpecificPrimitives.add("float"); + languageSpecificPrimitives.add("int"); + languageSpecificPrimitives.add("integer"); + languageSpecificPrimitives.add("long"); + languageSpecificPrimitives.add("number"); + languageSpecificPrimitives.add("object"); + languageSpecificPrimitives.add("short"); + languageSpecificPrimitives.add("string"); + // TODO: Fill this out. + } + + @Override + protected void initializeSpecialCharacterMapping() { + // escape only those symbols that can mess up markdown + specialCharReplacements.put("\\", "\\\\"); + specialCharReplacements.put("/", "\\/"); + specialCharReplacements.put("`", "\\`"); + specialCharReplacements.put("*", "\\*"); + specialCharReplacements.put("_", "\\_"); + specialCharReplacements.put("[", "\\["); + specialCharReplacements.put("]", "\\]"); + + // todo Current markdown api and model mustache templates display properties and parameters in tables. Pipe + // symbol in a table can be commonly escaped with a backslash (e.g. GFM supports this). However, in some cases + // it may be necessary to choose a different approach. + specialCharReplacements.put("|", "\\|"); + } + + /** + * Works identically to {@link DefaultCodegen#toParamName(String)} but doesn't camelize. + * + * @param name Codegen property object + * @return the sanitized parameter name + */ + @Override + public String toParamName(String name) { + if (reservedWords.contains(name)) { + return escapeReservedWord(name); + } else if (((CharSequence) name).chars().anyMatch(character -> specialCharReplacements.keySet().contains(String.valueOf((char) character)))) { + return escape(name, specialCharReplacements, null, null); + } + return name; + } + + @Override + public String toModelName(final String name) { + return name; + } + + @Override + public String toModelFilename(String name) { + return name; + } + + @Override + public GeneratorLanguage generatorLanguage() { return null; } + + @Override + public String escapeUnsafeCharacters(String input) { + // do nothing as the output is just doc + return input; + } + + @Override + public String escapeQuotationMark(String input) { + // do nothing as the output is just doc + return input; + } +} diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index 70a9b14b2446..875fd5ce7d43 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -138,3 +138,4 @@ org.openapitools.codegen.languages.TypeScriptReduxQueryClientCodegen org.openapitools.codegen.languages.TypeScriptRxjsClientCodegen org.openapitools.codegen.languages.WsdlSchemaCodegen org.openapitools.codegen.languages.XojoClientCodegen +org.openapitools.codegen.languages.ZapierClientCodegen diff --git a/modules/openapi-generator/src/main/resources/zapier/README.mustache b/modules/openapi-generator/src/main/resources/zapier/README.mustache new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/modules/openapi-generator/src/main/resources/zapier/api.mustache b/modules/openapi-generator/src/main/resources/zapier/api.mustache new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/modules/openapi-generator/src/main/resources/zapier/model.mustache b/modules/openapi-generator/src/main/resources/zapier/model.mustache new file mode 100644 index 000000000000..e69de29bb2d1 From 2b0325fc7db32bc27e671c8fd5ffa29c6dd485a1 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 26 Jun 2023 10:12:43 +0200 Subject: [PATCH 02/20] fixed zapier codegen --- .../languages/ZapierClientCodegen.java | 110 +++++++++++------- 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java index c46dfc3af1a1..8cb58b580cf3 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java @@ -1,11 +1,17 @@ package org.openapitools.codegen.languages; +import io.swagger.v3.oas.models.media.Schema; import org.openapitools.codegen.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; +import static org.openapitools.codegen.utils.StringUtils.camelize; import static org.openapitools.codegen.utils.StringUtils.escape; public class ZapierClientCodegen extends DefaultCodegen implements CodegenConfig { @@ -29,50 +35,49 @@ public ZapierClientCodegen() { super(); outputFolder = "generated-code" + File.separator + "zapier"; - modelTemplateFiles.put("model.mustache", ".zz"); - apiTemplateFiles.put("api.mustache", ".zz"); + modelTemplateFiles.put("model.mustache", ".js"); + apiTemplateFiles.put("api.mustache", ".js"); embeddedTemplateDir = templateDir = "zapier"; - apiPackage = "Apis"; - modelPackage = "Models"; - supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + apiPackage = "apis"; + modelPackage = "models"; + supportingFiles.add(new SupportingFile("actions.mustache", "operations", "actions.js")); + supportingFiles.add(new SupportingFile("utils.mustache", "utils", "utils.js")); + supportingFiles.add(new SupportingFile("index.mustache", "", "index.js")); + supportingFiles.add(new SupportingFile("authentication.mustache", "", "authentication.js")); + supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); languageSpecificPrimitives.clear(); - languageSpecificPrimitives.add("ByteArray"); - languageSpecificPrimitives.add("DateTime"); - languageSpecificPrimitives.add("URI"); - languageSpecificPrimitives.add("UUID"); - languageSpecificPrimitives.add("boolean"); - languageSpecificPrimitives.add("char"); - languageSpecificPrimitives.add("date"); - languageSpecificPrimitives.add("decimal"); - languageSpecificPrimitives.add("double"); - languageSpecificPrimitives.add("file"); - languageSpecificPrimitives.add("float"); - languageSpecificPrimitives.add("int"); - languageSpecificPrimitives.add("integer"); - languageSpecificPrimitives.add("long"); - languageSpecificPrimitives.add("number"); - languageSpecificPrimitives.add("object"); - languageSpecificPrimitives.add("short"); - languageSpecificPrimitives.add("string"); - // TODO: Fill this out. - } - - @Override - protected void initializeSpecialCharacterMapping() { - // escape only those symbols that can mess up markdown - specialCharReplacements.put("\\", "\\\\"); - specialCharReplacements.put("/", "\\/"); - specialCharReplacements.put("`", "\\`"); - specialCharReplacements.put("*", "\\*"); - specialCharReplacements.put("_", "\\_"); - specialCharReplacements.put("[", "\\["); - specialCharReplacements.put("]", "\\]"); - - // todo Current markdown api and model mustache templates display properties and parameters in tables. Pipe - // symbol in a table can be commonly escaped with a backslash (e.g. GFM supports this). However, in some cases - // it may be necessary to choose a different approach. - specialCharReplacements.put("|", "\\|"); + languageSpecificPrimitives = new HashSet<>( + Arrays.asList("number", "integer", "string", "boolean", "array", "file") + ); + + instantiationTypes.put("array", "array"); + instantiationTypes.put("set", "array"); + instantiationTypes.put("list", "array"); + instantiationTypes.put("map", "object"); + typeMapping = new HashMap<>(); + typeMapping.put("array", "array"); + typeMapping.put("set", "array"); + typeMapping.put("map", "object"); + typeMapping.put("List", "array"); + typeMapping.put("boolean", "boolean"); + typeMapping.put("string", "string"); + typeMapping.put("int", "integer"); + typeMapping.put("float", "number"); + typeMapping.put("number", "number"); + typeMapping.put("decimal", "number"); + typeMapping.put("DateTime", "string"); + typeMapping.put("date", "string"); + typeMapping.put("long", "number"); + typeMapping.put("short", "number"); + typeMapping.put("char", "string"); + typeMapping.put("double", "number"); + typeMapping.put("object", "object"); + typeMapping.put("integer", "integer"); + typeMapping.put("binary", "file"); + typeMapping.put("file", "file"); + typeMapping.put("UUID", "string"); + typeMapping.put("URI", "string"); } /** @@ -96,6 +101,29 @@ public String toModelName(final String name) { return name; } + @Override + public String toModelImport(String name) { + return "const " + name + " = " + "require('../" + modelPackage() + "/" + name + "');"; + } + + @Override + public String getSchemaType(Schema p) { + String openAPIType = super.getSchemaType(p); + String type = null; + if (typeMapping.containsKey(openAPIType)) { + type = typeMapping.get(openAPIType); + if (!needToImport(type)) { + return type; + } + } else { + type = openAPIType; + } + if (null == type) { + LOGGER.error("No Type defined for Schema {}", p); + } + return toModelName(type); + } + @Override public String toModelFilename(String name) { return name; From 171416bf3c42435731a1ecab5aa1ceb1d60430aa Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 26 Jun 2023 10:13:11 +0200 Subject: [PATCH 03/20] added zapier templates --- .../src/main/resources/zapier/README.mustache | 0 .../main/resources/zapier/actions.mustache | 23 +++++ .../src/main/resources/zapier/api.mustache | 83 ++++++++++++++++ .../resources/zapier/authentication.mustache | 4 + .../src/main/resources/zapier/index.mustache | 10 ++ .../src/main/resources/zapier/model.mustache | 97 +++++++++++++++++++ .../main/resources/zapier/package.mustache | 26 +++++ .../src/main/resources/zapier/utils.mustache | 23 +++++ 8 files changed, 266 insertions(+) delete mode 100644 modules/openapi-generator/src/main/resources/zapier/README.mustache create mode 100644 modules/openapi-generator/src/main/resources/zapier/actions.mustache create mode 100644 modules/openapi-generator/src/main/resources/zapier/authentication.mustache create mode 100644 modules/openapi-generator/src/main/resources/zapier/index.mustache create mode 100644 modules/openapi-generator/src/main/resources/zapier/package.mustache create mode 100644 modules/openapi-generator/src/main/resources/zapier/utils.mustache diff --git a/modules/openapi-generator/src/main/resources/zapier/README.mustache b/modules/openapi-generator/src/main/resources/zapier/README.mustache deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/modules/openapi-generator/src/main/resources/zapier/actions.mustache b/modules/openapi-generator/src/main/resources/zapier/actions.mustache new file mode 100644 index 000000000000..6dbe5f0e2f1e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/zapier/actions.mustache @@ -0,0 +1,23 @@ +{{#apiInfo}} +{{#apis}} +const {{classname}} = require('../{{apiPackage}}/{{classname}}'); +{{/apis}} +{{/apiInfo}} +const { searchMiddleware, hasASearchField, isSearchAction } = require('../utils/utils'); + +const actions = { + {{#apiInfo}} + {{#apis}} + {{#operations}} + {{#operation}} + [{{classname}}.{{operationId}}.key]: {{classname}}.{{operationId}}, + {{/operation}} + {{/operations}} + {{/apis}} + {{/apiInfo}} +} + +module.exports = { + searchActions: () => Object.entries(actions).reduce((actions, [key, value]) => isSearchAction(key) && hasASearchField(value) ? {...actions, [key]: searchMiddleware(value)} : actions, {}), + createActions: () => Object.entries(actions).reduce((actions, [key, value]) => !isSearchAction(key) ? {...actions, [key]: value} : actions, {}), +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/zapier/api.mustache b/modules/openapi-generator/src/main/resources/zapier/api.mustache index e69de29bb2d1..b88821d2d940 100644 --- a/modules/openapi-generator/src/main/resources/zapier/api.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/api.mustache @@ -0,0 +1,83 @@ +{{#imports}}{{{import}}} +{{/imports}} +const utils = require('../utils/utils'); + +{{#operations}} +module.exports = { +{{#operation}} + {{operationId}}: { + key: '{{operationId}}', + noun: '{{baseName}}', + display: { + label: '{{operationId}}', + description: '{{#notes}}{{.}}{{/notes}}', + hidden: false, + }, + operation: { + inputFields: [ + {{#allParams}} + {{#isPrimitiveType}} + { + key: '{{baseName}}', + label: '{{description}}', + type: '{{#isInteger}}integer{{/isInteger}}{{^isInteger}}{{#isNumeric}}number{{/isNumeric}}{{/isInteger}}{{#isString}}string{{/isString}}{{#isBoolean}}boolean{{/isBoolean}}{{#isDateTime}}datetime{{/isDateTime}}{{#isDate}}datetime{{/isDate}}{{#isFile}}file{{/isFile}}', + {{#required}} + required: true, + {{/required}} + {{#isEnum}} + choices: [ + {{#_enum}} + '{{.}}', + {{/_enum}} + ], + {{/isEnum}} + }, + {{/isPrimitiveType}} + {{^isPrimitiveType}} + ...{{baseType}}.fields(), + {{/isPrimitiveType}} + {{/allParams}} + ], + outputFields: [ + {{#returnType}} + {{^returnTypeIsPrimitive}} + ...{{returnType}}.fields('', false), + {{/returnTypeIsPrimitive}} + {{/returnType}} + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('{{basePath}}{{path}}'), + method: '{{httpMethod}}', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{=<% %>=}}{{bundle.authData.access_token}}<%={{ }}=%>', + 'Content-Type': '{{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}', + 'Accept': '{{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}', + }, + params: { + {{#allParams}} + {{#isQueryParam}} + '{{baseName}}': bundle.inputData?.['{{baseName}}'], + {{/isQueryParam}} + {{/allParams}} + }, + body: { + {{#allParams}} + {{#isBodyParam}} + {{#isPrimitiveType}}'{{baseName}}': bundle.inputData?.['{{baseName}}']{{/isPrimitiveType}}{{^isPrimitiveType}}...{{baseName}}.mapping(bundle){{/isPrimitiveType}}, + {{/isBodyParam}} + {{/allParams}} + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, +{{/operation}} +} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/zapier/authentication.mustache b/modules/openapi-generator/src/main/resources/zapier/authentication.mustache new file mode 100644 index 000000000000..8294e5fc99a6 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/zapier/authentication.mustache @@ -0,0 +1,4 @@ +module.exports = { + // TODO: autentication logic + // https://platform.zapier.com/cli_tutorials/getting-started#adding-authentication +}; \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/zapier/index.mustache b/modules/openapi-generator/src/main/resources/zapier/index.mustache new file mode 100644 index 000000000000..8f60b0c7b1e6 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/zapier/index.mustache @@ -0,0 +1,10 @@ +const authentication = require('./authentication'); +const { searchActions, createActions } = require('./operations/actions'); + +module.exports = { + version: require('./package.json').version, + platformVersion: require('zapier-platform-core').version, + authentication: authentication, + searches: searchActions(), + creates: createActions(), +}; diff --git a/modules/openapi-generator/src/main/resources/zapier/model.mustache b/modules/openapi-generator/src/main/resources/zapier/model.mustache index e69de29bb2d1..97b345026734 100644 --- a/modules/openapi-generator/src/main/resources/zapier/model.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/model.mustache @@ -0,0 +1,97 @@ +const _ = require('lodash') +const utils = require('../utils/utils'); +{{#imports}}{{{import}}} +{{/imports}} +{{#models}} +{{#model}} + +{{#isEnum}} +module.exports = { + fields: (key) => ( + { + label: `{{#description}}{{{.}}} - {{/description}}[${key}]`, + choices: [ + {{#allowableValues}} + {{#values}} + '{{.}}', + {{/values}} + {{/allowableValues}} + ], + } + ) + } +{{/isEnum}} +{{^isEnum}} +module.exports = { + fields: (prefix = '', isInput = true) => { + let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` + let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + return [ + {{#vars}} + {{#isPrimitiveType}} + { + key: `${keyPrefix}{{baseName}}`, + label: `{{#description}}{{{.}}} - {{/description}}[${labelPrefix}{{baseName}}]`, + {{#isArray}} + list: true, + type: '{{#items}}{{baseType}}{{/items}}', + {{/isArray}} + {{^isArray}} + type: '{{#isInteger}}integer{{/isInteger}}{{^isInteger}}{{#isNumeric}}number{{/isNumeric}}{{/isInteger}}{{#isString}}string{{/isString}}{{#isBoolean}}boolean{{/isBoolean}}{{#isDateTime}}datetime{{/isDateTime}}{{#isDate}}datetime{{/isDate}}{{#isFile}}file{{/isFile}}', + {{/isArray}} + {{#isEnum}} + choices: [ + {{#_enum}} + '{{.}}', + {{/_enum}} + ], + {{/isEnum}} + }, + {{/isPrimitiveType}} + {{^isPrimitiveType}} + {{#isArray}} + { + key: `${keyPrefix}{{baseName}}`,{{#items}}{{^isEnumRef}} + label: `{{#description}}{{{.}}} - {{/description}}[${labelPrefix}{{baseName}}]`, + children: {{complexType}}.fields(`${keyPrefix}{{baseName}}${!isInput && '[]'}`), {{/isEnumRef}}{{#isEnumRef}} + list: true, + type: 'string', + ...{{complexType}}.fields(`${keyPrefix}{{baseName}}`, isInput),{{/isEnumRef}}{{/items}} + }, + {{/isArray}} + {{^isArray}} + {{^allowableValues}} + {{#isFreeFormObject}} + { + key: `${keyPrefix}{{baseName}}`, + label: `{{#description}}{{{.}}} - {{/description}}[${labelPrefix}{{baseName}}]`, + dict: true, + }, + {{/isFreeFormObject}} + {{^isFreeFormObject}} + ...{{complexType}}.fields(`${keyPrefix}{{baseName}}`, isInput), + {{/isFreeFormObject}} + {{/allowableValues}} + {{#allowableValues}} + { + key: `${keyPrefix}{{baseName}}`, + ...{{complexType}}.fields(`${keyPrefix}{{baseName}}`, isInput), + }, + {{/allowableValues}} + {{/isArray}} + {{/isPrimitiveType}} + {{/vars}} + ] + }, + mapping: (bundle, prefix = '') => { + let keyPrefix = prefix && `${prefix}.` + return { + {{#vars}} + '{{baseName}}': {{#isPrimitiveType}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/isPrimitiveType}}{{^isPrimitiveType}}{{^allowableValues}}{{^isArray}}{{#isFreeFormObject}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/isFreeFormObject}}{{^isFreeFormObject}}utils.removeIfEmpty({{complexType}}.mapping(bundle, `${keyPrefix}{{baseName}}`)){{/isFreeFormObject}}{{/isArray}}{{#isArray}}utils.removeKeyPrefixes(bundle.inputData?.[`${keyPrefix}{{baseName}}`]){{/isArray}}{{/allowableValues}}{{#allowableValues}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/allowableValues}}{{/isPrimitiveType}}, + {{/vars}} + } + }, +} +{{/isEnum}} +{{/model}} +{{/models}} diff --git a/modules/openapi-generator/src/main/resources/zapier/package.mustache b/modules/openapi-generator/src/main/resources/zapier/package.mustache new file mode 100644 index 000000000000..af565854aba6 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/zapier/package.mustache @@ -0,0 +1,26 @@ +{ + "name": "{{npmName}}", + "version": "{{npmVersion}}", + "description": "OpenAPI client for {{npmName}}", + "author": "OpenAPI-Generator", + "main": "index.js", + "scripts": { + "test": "mocha --recursive -t 10000" + }, + "engines": { + "node": ">=v16", + "npm": ">=5.6.0" + }, + "dependencies": { + "lodash": "^4.17.21", + "zapier-platform-core": "14.1.1" + }, + "devDependencies": { + "mocha": "^10.2.0", + "should": "^13.2.0" + }, + "private": true, + "zapier": { + "convertedByCLIVersion": "14.1.1" + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/zapier/utils.mustache b/modules/openapi-generator/src/main/resources/zapier/utils.mustache new file mode 100644 index 000000000000..cfc027c9ad24 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/zapier/utils.mustache @@ -0,0 +1,23 @@ +const _ = require('lodash') + +const replacePathParameters = (url) => url.replace(/{([^{}]+)}/g, (keyExpr, key) => `{{bundle.inputData.${key}}}`) +const removeKeyPrefixes = (objectsArray) => objectsArray == undefined || typeof objectsArray[0] != 'object' ? objectsArray : objectsArray.map((obj) => Object.keys(obj).reduce((res, key) => (res[(key.split('.')).slice(-1)] = obj[key], res), {})) +const removeIfEmpty = (obj) => _.isEmpty(JSON.parse(JSON.stringify(obj))) ? undefined : obj +const hasASearchField = action => action.operation.inputFields.length > 0 +const isSearchAction = (key) => { + // TODO: custom logic + return false +} +const searchMiddleware = (action) => { + // TODO: custom logic + return action +} + +module.exports = { + replacePathParameters: replacePathParameters, + removeKeyPrefixes: removeKeyPrefixes, + removeIfEmpty: removeIfEmpty, + hasASearchField: hasASearchField, + isSearchAction: isSearchAction, + searchMiddleware: searchMiddleware, +} \ No newline at end of file From 18938edea9ef93b2148c58c7e79191b702f8cc2d Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 26 Jun 2023 10:13:45 +0200 Subject: [PATCH 04/20] added zapier sample --- bin/configs/zapier-petstore-new.yaml | 3 +- .../petstore/zapier/.openapi-generator-ignore | 23 ++ .../petstore/zapier/.openapi-generator/FILES | 14 + .../zapier/.openapi-generator/VERSION | 1 + samples/client/petstore/zapier/apis/PetApi.js | 357 ++++++++++++++++++ .../client/petstore/zapier/apis/StoreApi.js | 166 ++++++++ .../client/petstore/zapier/apis/UserApi.js | 334 ++++++++++++++++ .../client/petstore/zapier/authentication.js | 4 + samples/client/petstore/zapier/index.js | 10 + .../petstore/zapier/models/ApiResponse.js | 34 ++ .../client/petstore/zapier/models/Category.js | 28 ++ .../client/petstore/zapier/models/Order.js | 57 +++ samples/client/petstore/zapier/models/Pet.js | 56 +++ samples/client/petstore/zapier/models/Tag.js | 28 ++ samples/client/petstore/zapier/models/User.js | 64 ++++ .../petstore/zapier/operations/actions.js | 32 ++ samples/client/petstore/zapier/package.json | 26 ++ samples/client/petstore/zapier/utils/utils.js | 23 ++ 18 files changed, 1259 insertions(+), 1 deletion(-) create mode 100644 samples/client/petstore/zapier/.openapi-generator-ignore create mode 100644 samples/client/petstore/zapier/.openapi-generator/FILES create mode 100644 samples/client/petstore/zapier/.openapi-generator/VERSION create mode 100644 samples/client/petstore/zapier/apis/PetApi.js create mode 100644 samples/client/petstore/zapier/apis/StoreApi.js create mode 100644 samples/client/petstore/zapier/apis/UserApi.js create mode 100644 samples/client/petstore/zapier/authentication.js create mode 100644 samples/client/petstore/zapier/index.js create mode 100644 samples/client/petstore/zapier/models/ApiResponse.js create mode 100644 samples/client/petstore/zapier/models/Category.js create mode 100644 samples/client/petstore/zapier/models/Order.js create mode 100644 samples/client/petstore/zapier/models/Pet.js create mode 100644 samples/client/petstore/zapier/models/Tag.js create mode 100644 samples/client/petstore/zapier/models/User.js create mode 100644 samples/client/petstore/zapier/operations/actions.js create mode 100644 samples/client/petstore/zapier/package.json create mode 100644 samples/client/petstore/zapier/utils/utils.js diff --git a/bin/configs/zapier-petstore-new.yaml b/bin/configs/zapier-petstore-new.yaml index 37f67475ce91..b57c95948506 100644 --- a/bin/configs/zapier-petstore-new.yaml +++ b/bin/configs/zapier-petstore-new.yaml @@ -3,4 +3,5 @@ outputDir: samples/client/petstore/zapier inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml templateDir: modules/openapi-generator/src/main/resources/zapier additionalProperties: - hideGenerationTimestamp: "true" + npmVersion: 0.0.1 + npmName: '@openapitools/zapier' \ No newline at end of file diff --git a/samples/client/petstore/zapier/.openapi-generator-ignore b/samples/client/petstore/zapier/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/client/petstore/zapier/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/client/petstore/zapier/.openapi-generator/FILES b/samples/client/petstore/zapier/.openapi-generator/FILES new file mode 100644 index 000000000000..29a34b32c746 --- /dev/null +++ b/samples/client/petstore/zapier/.openapi-generator/FILES @@ -0,0 +1,14 @@ +apis/PetApi.js +apis/StoreApi.js +apis/UserApi.js +authentication.js +index.js +models/ApiResponse.js +models/Category.js +models/Order.js +models/Pet.js +models/Tag.js +models/User.js +operations/actions.js +package.json +utils/utils.js diff --git a/samples/client/petstore/zapier/.openapi-generator/VERSION b/samples/client/petstore/zapier/.openapi-generator/VERSION new file mode 100644 index 000000000000..757e67400401 --- /dev/null +++ b/samples/client/petstore/zapier/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.0.0-SNAPSHOT \ No newline at end of file diff --git a/samples/client/petstore/zapier/apis/PetApi.js b/samples/client/petstore/zapier/apis/PetApi.js new file mode 100644 index 000000000000..791f60f53fe9 --- /dev/null +++ b/samples/client/petstore/zapier/apis/PetApi.js @@ -0,0 +1,357 @@ +const ApiResponse = require('../models/ApiResponse'); +const Pet = require('../models/Pet'); +const utils = require('../utils/utils'); + +module.exports = { + addPet: { + key: 'addPet', + noun: 'Pet', + display: { + label: 'addPet', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + ...Pet.fields(), + ], + outputFields: [ + ...Pet.fields('', false), + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/pet'), + method: 'POST', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': 'application/json, application/xml', + 'Accept': 'application/xml, application/json', + }, + params: { + }, + body: { + ...Pet.mapping(bundle), + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + deletePet: { + key: 'deletePet', + noun: 'Pet', + display: { + label: 'deletePet', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'petId', + label: 'Pet id to delete', + type: '', + required: true, + }, + { + key: 'api_key', + label: '', + type: 'string', + }, + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/pet/{petId}'), + method: 'DELETE', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': '', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + findPetsByStatus: { + key: 'findPetsByStatus', + noun: 'Pet', + display: { + label: 'findPetsByStatus', + description: 'Multiple status values can be provided with comma separated strings', + hidden: false, + }, + operation: { + inputFields: [ + ...string.fields(), + ], + outputFields: [ + ...array.fields('', false), + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/pet/findByStatus'), + method: 'GET', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': 'application/xml, application/json', + }, + params: { + 'status': bundle.inputData?.['status'], + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + findPetsByTags: { + key: 'findPetsByTags', + noun: 'Pet', + display: { + label: 'findPetsByTags', + description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.', + hidden: false, + }, + operation: { + inputFields: [ + ...string.fields(), + ], + outputFields: [ + ...array.fields('', false), + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/pet/findByTags'), + method: 'GET', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': 'application/xml, application/json', + }, + params: { + 'tags': bundle.inputData?.['tags'], + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + getPetById: { + key: 'getPetById', + noun: 'Pet', + display: { + label: 'getPetById', + description: 'Returns a single pet', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'petId', + label: 'ID of pet to return', + type: '', + required: true, + }, + ], + outputFields: [ + ...Pet.fields('', false), + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/pet/{petId}'), + method: 'GET', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': 'application/xml, application/json', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + updatePet: { + key: 'updatePet', + noun: 'Pet', + display: { + label: 'updatePet', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + ...Pet.fields(), + ], + outputFields: [ + ...Pet.fields('', false), + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/pet'), + method: 'PUT', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': 'application/json, application/xml', + 'Accept': 'application/xml, application/json', + }, + params: { + }, + body: { + ...Pet.mapping(bundle), + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + updatePetWithForm: { + key: 'updatePetWithForm', + noun: 'Pet', + display: { + label: 'updatePetWithForm', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'petId', + label: 'ID of pet that needs to be updated', + type: '', + required: true, + }, + { + key: 'name', + label: 'Updated name of the pet', + type: 'string', + }, + { + key: 'status', + label: 'Updated status of the pet', + type: 'string', + }, + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/pet/{petId}'), + method: 'POST', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': '', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + uploadFile: { + key: 'uploadFile', + noun: 'Pet', + display: { + label: 'uploadFile', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'petId', + label: 'ID of pet to update', + type: '', + required: true, + }, + { + key: 'additionalMetadata', + label: 'Additional data to pass to server', + type: 'string', + }, + { + key: 'file', + label: 'file to upload', + type: 'file', + }, + ], + outputFields: [ + ...ApiResponse.fields('', false), + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/pet/{petId}/uploadImage'), + method: 'POST', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': 'multipart/form-data', + 'Accept': 'application/json', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, +} diff --git a/samples/client/petstore/zapier/apis/StoreApi.js b/samples/client/petstore/zapier/apis/StoreApi.js new file mode 100644 index 000000000000..2ef67344374b --- /dev/null +++ b/samples/client/petstore/zapier/apis/StoreApi.js @@ -0,0 +1,166 @@ +const Order = require('../models/Order'); +const object = require('../models/object'); +const utils = require('../utils/utils'); + +module.exports = { + deleteOrder: { + key: 'deleteOrder', + noun: 'Store', + display: { + label: 'deleteOrder', + description: 'For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'orderId', + label: 'ID of the order that needs to be deleted', + type: 'string', + required: true, + }, + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/store/order/{orderId}'), + method: 'DELETE', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': '', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + getInventory: { + key: 'getInventory', + noun: 'Store', + display: { + label: 'getInventory', + description: 'Returns a map of status codes to quantities', + hidden: false, + }, + operation: { + inputFields: [ + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/store/inventory'), + method: 'GET', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': 'application/json', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + getOrderById: { + key: 'getOrderById', + noun: 'Store', + display: { + label: 'getOrderById', + description: 'For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'orderId', + label: 'ID of pet that needs to be fetched', + type: '', + required: true, + }, + ], + outputFields: [ + ...Order.fields('', false), + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/store/order/{orderId}'), + method: 'GET', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': 'application/xml, application/json', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + placeOrder: { + key: 'placeOrder', + noun: 'Store', + display: { + label: 'placeOrder', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + ...Order.fields(), + ], + outputFields: [ + ...Order.fields('', false), + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/store/order'), + method: 'POST', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': 'application/json', + 'Accept': 'application/xml, application/json', + }, + params: { + }, + body: { + ...Order.mapping(bundle), + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, +} diff --git a/samples/client/petstore/zapier/apis/UserApi.js b/samples/client/petstore/zapier/apis/UserApi.js new file mode 100644 index 000000000000..0419332bbdde --- /dev/null +++ b/samples/client/petstore/zapier/apis/UserApi.js @@ -0,0 +1,334 @@ +const User = require('../models/User'); +const utils = require('../utils/utils'); + +module.exports = { + createUser: { + key: 'createUser', + noun: 'User', + display: { + label: 'createUser', + description: 'This can only be done by the logged in user.', + hidden: false, + }, + operation: { + inputFields: [ + ...User.fields(), + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/user'), + method: 'POST', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': 'application/json', + 'Accept': '', + }, + params: { + }, + body: { + ...User.mapping(bundle), + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + createUsersWithArrayInput: { + key: 'createUsersWithArrayInput', + noun: 'User', + display: { + label: 'createUsersWithArrayInput', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + ...User.fields(), + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/user/createWithArray'), + method: 'POST', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': 'application/json', + 'Accept': '', + }, + params: { + }, + body: { + ...User.mapping(bundle), + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + createUsersWithListInput: { + key: 'createUsersWithListInput', + noun: 'User', + display: { + label: 'createUsersWithListInput', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + ...User.fields(), + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/user/createWithList'), + method: 'POST', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': 'application/json', + 'Accept': '', + }, + params: { + }, + body: { + ...User.mapping(bundle), + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + deleteUser: { + key: 'deleteUser', + noun: 'User', + display: { + label: 'deleteUser', + description: 'This can only be done by the logged in user.', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'username', + label: 'The name that needs to be deleted', + type: 'string', + required: true, + }, + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/user/{username}'), + method: 'DELETE', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': '', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + getUserByName: { + key: 'getUserByName', + noun: 'User', + display: { + label: 'getUserByName', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'username', + label: 'The name that needs to be fetched. Use user1 for testing.', + type: 'string', + required: true, + }, + ], + outputFields: [ + ...User.fields('', false), + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/user/{username}'), + method: 'GET', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': 'application/xml, application/json', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + loginUser: { + key: 'loginUser', + noun: 'User', + display: { + label: 'loginUser', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'username', + label: 'The user name for login', + type: 'string', + required: true, + }, + { + key: 'password', + label: 'The password for login in clear text', + type: 'string', + required: true, + }, + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/user/login'), + method: 'GET', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': 'application/xml, application/json', + }, + params: { + 'username': bundle.inputData?.['username'], + 'password': bundle.inputData?.['password'], + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + logoutUser: { + key: 'logoutUser', + noun: 'User', + display: { + label: 'logoutUser', + description: '', + hidden: false, + }, + operation: { + inputFields: [ + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/user/logout'), + method: 'GET', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': '', + 'Accept': '', + }, + params: { + }, + body: { + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, + updateUser: { + key: 'updateUser', + noun: 'User', + display: { + label: 'updateUser', + description: 'This can only be done by the logged in user.', + hidden: false, + }, + operation: { + inputFields: [ + { + key: 'username', + label: 'name that need to be deleted', + type: 'string', + required: true, + }, + ...User.fields(), + ], + outputFields: [ + ], + perform: async (z, bundle) => { + const options = { + url: utils.replacePathParameters('http://petstore.swagger.io/v2/user/{username}'), + method: 'PUT', + removeMissingValuesFrom: { params: true, body: true }, + headers: { + 'Authorization': 'Bearer {{bundle.authData.access_token}}', + 'Content-Type': 'application/json', + 'Accept': '', + }, + params: { + }, + body: { + ...User.mapping(bundle), + }, + } + return z.request(options).then((response) => { + response.throwForStatus(); + const results = response.json; + return results; + }) + } + } + }, +} diff --git a/samples/client/petstore/zapier/authentication.js b/samples/client/petstore/zapier/authentication.js new file mode 100644 index 000000000000..8294e5fc99a6 --- /dev/null +++ b/samples/client/petstore/zapier/authentication.js @@ -0,0 +1,4 @@ +module.exports = { + // TODO: autentication logic + // https://platform.zapier.com/cli_tutorials/getting-started#adding-authentication +}; \ No newline at end of file diff --git a/samples/client/petstore/zapier/index.js b/samples/client/petstore/zapier/index.js new file mode 100644 index 000000000000..8f60b0c7b1e6 --- /dev/null +++ b/samples/client/petstore/zapier/index.js @@ -0,0 +1,10 @@ +const authentication = require('./authentication'); +const { searchActions, createActions } = require('./operations/actions'); + +module.exports = { + version: require('./package.json').version, + platformVersion: require('zapier-platform-core').version, + authentication: authentication, + searches: searchActions(), + creates: createActions(), +}; diff --git a/samples/client/petstore/zapier/models/ApiResponse.js b/samples/client/petstore/zapier/models/ApiResponse.js new file mode 100644 index 000000000000..f5e2f01e41ac --- /dev/null +++ b/samples/client/petstore/zapier/models/ApiResponse.js @@ -0,0 +1,34 @@ +const _ = require('lodash') +const utils = require('../utils/utils'); + +module.exports = { + fields: (prefix = '', isInput = true) => { + let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` + let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + return [ + { + key: `${keyPrefix}code`, + label: `[${labelPrefix}code]`, + type: 'integer', + }, + { + key: `${keyPrefix}type`, + label: `[${labelPrefix}type]`, + type: 'string', + }, + { + key: `${keyPrefix}message`, + label: `[${labelPrefix}message]`, + type: 'string', + }, + ] + }, + mapping: (bundle, prefix = '') => { + let keyPrefix = prefix && `${prefix}.` + return { + 'code': bundle.inputData?.[`${keyPrefix}code`], + 'type': bundle.inputData?.[`${keyPrefix}type`], + 'message': bundle.inputData?.[`${keyPrefix}message`], + } + }, +} diff --git a/samples/client/petstore/zapier/models/Category.js b/samples/client/petstore/zapier/models/Category.js new file mode 100644 index 000000000000..ce2097ffed05 --- /dev/null +++ b/samples/client/petstore/zapier/models/Category.js @@ -0,0 +1,28 @@ +const _ = require('lodash') +const utils = require('../utils/utils'); + +module.exports = { + fields: (prefix = '', isInput = true) => { + let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` + let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + return [ + { + key: `${keyPrefix}id`, + label: `[${labelPrefix}id]`, + type: 'number', + }, + { + key: `${keyPrefix}name`, + label: `[${labelPrefix}name]`, + type: 'string', + }, + ] + }, + mapping: (bundle, prefix = '') => { + let keyPrefix = prefix && `${prefix}.` + return { + 'id': bundle.inputData?.[`${keyPrefix}id`], + 'name': bundle.inputData?.[`${keyPrefix}name`], + } + }, +} diff --git a/samples/client/petstore/zapier/models/Order.js b/samples/client/petstore/zapier/models/Order.js new file mode 100644 index 000000000000..764b03bc7ea9 --- /dev/null +++ b/samples/client/petstore/zapier/models/Order.js @@ -0,0 +1,57 @@ +const _ = require('lodash') +const utils = require('../utils/utils'); + +module.exports = { + fields: (prefix = '', isInput = true) => { + let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` + let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + return [ + { + key: `${keyPrefix}id`, + label: `[${labelPrefix}id]`, + type: 'number', + }, + { + key: `${keyPrefix}petId`, + label: `[${labelPrefix}petId]`, + type: 'number', + }, + { + key: `${keyPrefix}quantity`, + label: `[${labelPrefix}quantity]`, + type: 'integer', + }, + { + key: `${keyPrefix}shipDate`, + label: `[${labelPrefix}shipDate]`, + type: 'datetime', + }, + { + key: `${keyPrefix}status`, + label: `Order Status - [${labelPrefix}status]`, + type: 'string', + choices: [ + 'placed', + 'approved', + 'delivered', + ], + }, + { + key: `${keyPrefix}complete`, + label: `[${labelPrefix}complete]`, + type: 'boolean', + }, + ] + }, + mapping: (bundle, prefix = '') => { + let keyPrefix = prefix && `${prefix}.` + return { + 'id': bundle.inputData?.[`${keyPrefix}id`], + 'petId': bundle.inputData?.[`${keyPrefix}petId`], + 'quantity': bundle.inputData?.[`${keyPrefix}quantity`], + 'shipDate': bundle.inputData?.[`${keyPrefix}shipDate`], + 'status': bundle.inputData?.[`${keyPrefix}status`], + 'complete': bundle.inputData?.[`${keyPrefix}complete`], + } + }, +} diff --git a/samples/client/petstore/zapier/models/Pet.js b/samples/client/petstore/zapier/models/Pet.js new file mode 100644 index 000000000000..fceb76c03257 --- /dev/null +++ b/samples/client/petstore/zapier/models/Pet.js @@ -0,0 +1,56 @@ +const _ = require('lodash') +const utils = require('../utils/utils'); +const Category = require('../models/Category'); +const Tag = require('../models/Tag'); + +module.exports = { + fields: (prefix = '', isInput = true) => { + let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` + let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + return [ + { + key: `${keyPrefix}id`, + label: `[${labelPrefix}id]`, + type: 'number', + }, + ...Category.fields(`${keyPrefix}category`, isInput), + { + key: `${keyPrefix}name`, + label: `[${labelPrefix}name]`, + type: 'string', + }, + { + key: `${keyPrefix}photoUrls`, + label: `[${labelPrefix}photoUrls]`, + list: true, + type: 'string', + }, + { + key: `${keyPrefix}tags`, + label: `[${labelPrefix}tags]`, + children: Tag.fields(`${keyPrefix}tags${!isInput && '[]'}`), + }, + { + key: `${keyPrefix}status`, + label: `pet status in the store - [${labelPrefix}status]`, + type: 'string', + choices: [ + 'available', + 'pending', + 'sold', + ], + }, + ] + }, + mapping: (bundle, prefix = '') => { + let keyPrefix = prefix && `${prefix}.` + return { + 'id': bundle.inputData?.[`${keyPrefix}id`], + 'category': utils.removeIfEmpty(Category.mapping(bundle, `${keyPrefix}category`)), + 'name': bundle.inputData?.[`${keyPrefix}name`], + 'photoUrls': bundle.inputData?.[`${keyPrefix}photoUrls`], + 'tags': utils.removeKeyPrefixes(bundle.inputData?.[`${keyPrefix}tags`]), + 'status': bundle.inputData?.[`${keyPrefix}status`], + } + }, +} diff --git a/samples/client/petstore/zapier/models/Tag.js b/samples/client/petstore/zapier/models/Tag.js new file mode 100644 index 000000000000..ce2097ffed05 --- /dev/null +++ b/samples/client/petstore/zapier/models/Tag.js @@ -0,0 +1,28 @@ +const _ = require('lodash') +const utils = require('../utils/utils'); + +module.exports = { + fields: (prefix = '', isInput = true) => { + let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` + let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + return [ + { + key: `${keyPrefix}id`, + label: `[${labelPrefix}id]`, + type: 'number', + }, + { + key: `${keyPrefix}name`, + label: `[${labelPrefix}name]`, + type: 'string', + }, + ] + }, + mapping: (bundle, prefix = '') => { + let keyPrefix = prefix && `${prefix}.` + return { + 'id': bundle.inputData?.[`${keyPrefix}id`], + 'name': bundle.inputData?.[`${keyPrefix}name`], + } + }, +} diff --git a/samples/client/petstore/zapier/models/User.js b/samples/client/petstore/zapier/models/User.js new file mode 100644 index 000000000000..fc94a6fd567c --- /dev/null +++ b/samples/client/petstore/zapier/models/User.js @@ -0,0 +1,64 @@ +const _ = require('lodash') +const utils = require('../utils/utils'); + +module.exports = { + fields: (prefix = '', isInput = true) => { + let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` + let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + return [ + { + key: `${keyPrefix}id`, + label: `[${labelPrefix}id]`, + type: 'number', + }, + { + key: `${keyPrefix}username`, + label: `[${labelPrefix}username]`, + type: 'string', + }, + { + key: `${keyPrefix}firstName`, + label: `[${labelPrefix}firstName]`, + type: 'string', + }, + { + key: `${keyPrefix}lastName`, + label: `[${labelPrefix}lastName]`, + type: 'string', + }, + { + key: `${keyPrefix}email`, + label: `[${labelPrefix}email]`, + type: 'string', + }, + { + key: `${keyPrefix}password`, + label: `[${labelPrefix}password]`, + type: 'string', + }, + { + key: `${keyPrefix}phone`, + label: `[${labelPrefix}phone]`, + type: 'string', + }, + { + key: `${keyPrefix}userStatus`, + label: `User Status - [${labelPrefix}userStatus]`, + type: 'integer', + }, + ] + }, + mapping: (bundle, prefix = '') => { + let keyPrefix = prefix && `${prefix}.` + return { + 'id': bundle.inputData?.[`${keyPrefix}id`], + 'username': bundle.inputData?.[`${keyPrefix}username`], + 'firstName': bundle.inputData?.[`${keyPrefix}firstName`], + 'lastName': bundle.inputData?.[`${keyPrefix}lastName`], + 'email': bundle.inputData?.[`${keyPrefix}email`], + 'password': bundle.inputData?.[`${keyPrefix}password`], + 'phone': bundle.inputData?.[`${keyPrefix}phone`], + 'userStatus': bundle.inputData?.[`${keyPrefix}userStatus`], + } + }, +} diff --git a/samples/client/petstore/zapier/operations/actions.js b/samples/client/petstore/zapier/operations/actions.js new file mode 100644 index 000000000000..e6d77cdb53e3 --- /dev/null +++ b/samples/client/petstore/zapier/operations/actions.js @@ -0,0 +1,32 @@ +const PetApi = require('../apis/PetApi'); +const StoreApi = require('../apis/StoreApi'); +const UserApi = require('../apis/UserApi'); +const { searchMiddleware, hasASearchField, isSearchAction } = require('../utils/utils'); + +const actions = { + [PetApi.addPet.key]: PetApi.addPet, + [PetApi.deletePet.key]: PetApi.deletePet, + [PetApi.findPetsByStatus.key]: PetApi.findPetsByStatus, + [PetApi.findPetsByTags.key]: PetApi.findPetsByTags, + [PetApi.getPetById.key]: PetApi.getPetById, + [PetApi.updatePet.key]: PetApi.updatePet, + [PetApi.updatePetWithForm.key]: PetApi.updatePetWithForm, + [PetApi.uploadFile.key]: PetApi.uploadFile, + [StoreApi.deleteOrder.key]: StoreApi.deleteOrder, + [StoreApi.getInventory.key]: StoreApi.getInventory, + [StoreApi.getOrderById.key]: StoreApi.getOrderById, + [StoreApi.placeOrder.key]: StoreApi.placeOrder, + [UserApi.createUser.key]: UserApi.createUser, + [UserApi.createUsersWithArrayInput.key]: UserApi.createUsersWithArrayInput, + [UserApi.createUsersWithListInput.key]: UserApi.createUsersWithListInput, + [UserApi.deleteUser.key]: UserApi.deleteUser, + [UserApi.getUserByName.key]: UserApi.getUserByName, + [UserApi.loginUser.key]: UserApi.loginUser, + [UserApi.logoutUser.key]: UserApi.logoutUser, + [UserApi.updateUser.key]: UserApi.updateUser, +} + +module.exports = { + searchActions: () => Object.entries(actions).reduce((actions, [key, value]) => isSearchAction(key) && hasASearchField(value) ? {...actions, [key]: searchMiddleware(value)} : actions, {}), + createActions: () => Object.entries(actions).reduce((actions, [key, value]) => !isSearchAction(key) ? {...actions, [key]: value} : actions, {}), +} \ No newline at end of file diff --git a/samples/client/petstore/zapier/package.json b/samples/client/petstore/zapier/package.json new file mode 100644 index 000000000000..104976d509b7 --- /dev/null +++ b/samples/client/petstore/zapier/package.json @@ -0,0 +1,26 @@ +{ + "name": "@openapitools/zapier", + "version": "0.0.1", + "description": "OpenAPI client for @openapitools/zapier", + "author": "OpenAPI-Generator", + "main": "index.js", + "scripts": { + "test": "mocha --recursive -t 10000" + }, + "engines": { + "node": ">=v16", + "npm": ">=5.6.0" + }, + "dependencies": { + "lodash": "^4.17.21", + "zapier-platform-core": "14.1.1" + }, + "devDependencies": { + "mocha": "^10.2.0", + "should": "^13.2.0" + }, + "private": true, + "zapier": { + "convertedByCLIVersion": "14.1.1" + } +} \ No newline at end of file diff --git a/samples/client/petstore/zapier/utils/utils.js b/samples/client/petstore/zapier/utils/utils.js new file mode 100644 index 000000000000..cfc027c9ad24 --- /dev/null +++ b/samples/client/petstore/zapier/utils/utils.js @@ -0,0 +1,23 @@ +const _ = require('lodash') + +const replacePathParameters = (url) => url.replace(/{([^{}]+)}/g, (keyExpr, key) => `{{bundle.inputData.${key}}}`) +const removeKeyPrefixes = (objectsArray) => objectsArray == undefined || typeof objectsArray[0] != 'object' ? objectsArray : objectsArray.map((obj) => Object.keys(obj).reduce((res, key) => (res[(key.split('.')).slice(-1)] = obj[key], res), {})) +const removeIfEmpty = (obj) => _.isEmpty(JSON.parse(JSON.stringify(obj))) ? undefined : obj +const hasASearchField = action => action.operation.inputFields.length > 0 +const isSearchAction = (key) => { + // TODO: custom logic + return false +} +const searchMiddleware = (action) => { + // TODO: custom logic + return action +} + +module.exports = { + replacePathParameters: replacePathParameters, + removeKeyPrefixes: removeKeyPrefixes, + removeIfEmpty: removeIfEmpty, + hasASearchField: hasASearchField, + isSearchAction: isSearchAction, + searchMiddleware: searchMiddleware, +} \ No newline at end of file From e324f022bdb5f552e845fd70d70add967927ede0 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 26 Jun 2023 10:34:13 +0200 Subject: [PATCH 05/20] added zapier doc --- docs/generators.md | 1 + docs/generators/zapier.md | 177 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 docs/generators/zapier.md diff --git a/docs/generators.md b/docs/generators.md index af92241c4842..fac5916ded14 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -72,6 +72,7 @@ The following generators are available: * [typescript-redux-query](generators/typescript-redux-query.md) * [typescript-rxjs](generators/typescript-rxjs.md) * [xojo-client](generators/xojo-client.md) +* [zapier](generators/zapier.md) ## SERVER generators diff --git a/docs/generators/zapier.md b/docs/generators/zapier.md new file mode 100644 index 000000000000..c932be7e2d32 --- /dev/null +++ b/docs/generators/zapier.md @@ -0,0 +1,177 @@ +--- +title: Documentation for the zapier Generator +--- + +## METADATA + +| Property | Value | Notes | +| -------- | ----- | ----- | +| generator name | zapier | pass this to the generate command after -g | +| generator stability | STABLE | | +| generator type | CLIENT | | +| generator default templating engine | mustache | | +| helpTxt | Generates a zapier client. | | + +## CONFIG OPTIONS +These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details. + +| Option | Description | Values | Default | +| ------ | ----------- | ------ | ------- | +|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false| +|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|
**false**
The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.
**true**
Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.
|true| +|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true| +|enumUnknownDefaultCase|If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response.With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the server sends an enum case that is not known by the client/spec, they can safely fallback to this case.|
**false**
No changes to the enum's are made, this is the default option.
**true**
With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the enum case sent by the server is not known by the client/spec, can safely be decoded to this case.
|false| +|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C# have this enabled by default).|
**true**
The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.
**false**
The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.
|true| +|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false| +|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true| +|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| + +## IMPORT MAPPING + +| Type/Alias | Imports | +| ---------- | ------- | + + +## INSTANTIATION TYPES + +| Type/Alias | Instantiated By | +| ---------- | --------------- | +|array|array| +|list|array| +|map|object| +|set|array| + + +## LANGUAGE PRIMITIVES + +
    +
  • array
  • +
  • boolean
  • +
  • file
  • +
  • integer
  • +
  • number
  • +
  • string
  • +
+ +## RESERVED WORDS + +
    +
+ +## FEATURE SET + + +### Client Modification Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|BasePath|✗|ToolingExtension +|Authorizations|✗|ToolingExtension +|UserAgent|✗|ToolingExtension +|MockServer|✗|ToolingExtension + +### Data Type Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Custom|✗|OAS2,OAS3 +|Int32|✓|OAS2,OAS3 +|Int64|✓|OAS2,OAS3 +|Float|✓|OAS2,OAS3 +|Double|✓|OAS2,OAS3 +|Decimal|✓|ToolingExtension +|String|✓|OAS2,OAS3 +|Byte|✓|OAS2,OAS3 +|Binary|✓|OAS2,OAS3 +|Boolean|✓|OAS2,OAS3 +|Date|✓|OAS2,OAS3 +|DateTime|✓|OAS2,OAS3 +|Password|✓|OAS2,OAS3 +|File|✓|OAS2 +|Uuid|✗| +|Array|✓|OAS2,OAS3 +|Null|✗|OAS3 +|AnyType|✗|OAS2,OAS3 +|Object|✓|OAS2,OAS3 +|Maps|✓|ToolingExtension +|CollectionFormat|✓|OAS2 +|CollectionFormatMulti|✓|OAS2 +|Enum|✓|OAS2,OAS3 +|ArrayOfEnum|✓|ToolingExtension +|ArrayOfModel|✓|ToolingExtension +|ArrayOfCollectionOfPrimitives|✓|ToolingExtension +|ArrayOfCollectionOfModel|✓|ToolingExtension +|ArrayOfCollectionOfEnum|✓|ToolingExtension +|MapOfEnum|✓|ToolingExtension +|MapOfModel|✓|ToolingExtension +|MapOfCollectionOfPrimitives|✓|ToolingExtension +|MapOfCollectionOfModel|✓|ToolingExtension +|MapOfCollectionOfEnum|✓|ToolingExtension + +### Documentation Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Readme|✗|ToolingExtension +|Model|✓|ToolingExtension +|Api|✓|ToolingExtension + +### Global Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Host|✓|OAS2,OAS3 +|BasePath|✓|OAS2,OAS3 +|Info|✓|OAS2,OAS3 +|Schemes|✗|OAS2,OAS3 +|PartialSchemes|✓|OAS2,OAS3 +|Consumes|✓|OAS2 +|Produces|✓|OAS2 +|ExternalDocumentation|✓|OAS2,OAS3 +|Examples|✓|OAS2,OAS3 +|XMLStructureDefinitions|✗|OAS2,OAS3 +|MultiServer|✗|OAS3 +|ParameterizedServer|✗|OAS3 +|ParameterStyling|✗|OAS3 +|Callbacks|✓|OAS3 +|LinkObjects|✗|OAS3 + +### Parameter Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Path|✓|OAS2,OAS3 +|Query|✓|OAS2,OAS3 +|Header|✓|OAS2,OAS3 +|Body|✓|OAS2 +|FormUnencoded|✓|OAS2 +|FormMultipart|✓|OAS2 +|Cookie|✓|OAS3 + +### Schema Support Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|Simple|✓|OAS2,OAS3 +|Composite|✓|OAS2,OAS3 +|Polymorphism|✓|OAS2,OAS3 +|Union|✗|OAS3 +|allOf|✗|OAS2,OAS3 +|anyOf|✗|OAS3 +|oneOf|✗|OAS3 +|not|✗|OAS3 + +### Security Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|BasicAuth|✓|OAS2,OAS3 +|ApiKey|✓|OAS2,OAS3 +|OpenIDConnect|✗|OAS3 +|BearerToken|✓|OAS3 +|OAuth2_Implicit|✓|OAS2,OAS3 +|OAuth2_Password|✓|OAS2,OAS3 +|OAuth2_ClientCredentials|✓|OAS2,OAS3 +|OAuth2_AuthorizationCode|✓|OAS2,OAS3 +|SignatureAuth|✗|OAS3 + +### Wire Format Feature +| Name | Supported | Defined By | +| ---- | --------- | ---------- | +|JSON|✓|OAS2,OAS3 +|XML|✓|OAS2,OAS3 +|PROTOBUF|✗|ToolingExtension +|Custom|✗|OAS2,OAS3 From 6a84eca68477a9d5fdd97df6c8afa1a03be68221 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Wed, 28 Jun 2023 10:36:30 +0200 Subject: [PATCH 06/20] added zapier generator form data management --- .../src/main/resources/zapier/api.mustache | 29 ++++++++++++++++--- .../main/resources/zapier/package.mustache | 3 +- samples/client/petstore/zapier/apis/PetApi.js | 10 +++++-- samples/client/petstore/zapier/package.json | 3 +- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/zapier/api.mustache b/modules/openapi-generator/src/main/resources/zapier/api.mustache index b88821d2d940..fea0f8efd49a 100644 --- a/modules/openapi-generator/src/main/resources/zapier/api.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/api.mustache @@ -1,8 +1,15 @@ {{#imports}}{{{import}}} {{/imports}} const utils = require('../utils/utils'); - {{#operations}} +{{#operation}} +{{#isMultipart}} +const FormData = require('form-data'); +{{/isMultipart}} +{{/operation}} +{{/operations}} +{{#operations}} + module.exports = { {{#operation}} {{operationId}}: { @@ -46,13 +53,27 @@ module.exports = { {{/returnType}} ], perform: async (z, bundle) => { + {{#isMultipart}} + const formData = new FormData() + {{#allParams}} + {{#isFormParam}} + {{^isFile}} + formData.append('{{baseName}}', bundle.inputData?.['{{baseName}}']) + {{/isFile}} + {{#isFile}} + const filename = bundle.inputData?.['filename'] || bundle.inputData?.['{{baseName}}'].split('/').slice(-1)[0] + formData.append('{{baseName}}', (await (await z.request({url: bundle.inputData?.['{{baseName}}'], method: 'GET', raw: true})).buffer()), { filename: filename }) + {{/isFile}} + {{/isFormParam}} + {{/allParams}} + {{/isMultipart}} const options = { url: utils.replacePathParameters('{{basePath}}{{path}}'), method: '{{httpMethod}}', removeMissingValuesFrom: { params: true, body: true }, headers: { 'Authorization': 'Bearer {{=<% %>=}}{{bundle.authData.access_token}}<%={{ }}=%>', - 'Content-Type': '{{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}', + {{^isMultipart}}'Content-Type': '{{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}',{{/isMultipart}} 'Accept': '{{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}', }, params: { @@ -62,13 +83,13 @@ module.exports = { {{/isQueryParam}} {{/allParams}} }, - body: { + body: {{#isMultipart}}formData,{{/isMultipart}}{{^isMultipart}}{ {{#allParams}} {{#isBodyParam}} {{#isPrimitiveType}}'{{baseName}}': bundle.inputData?.['{{baseName}}']{{/isPrimitiveType}}{{^isPrimitiveType}}...{{baseName}}.mapping(bundle){{/isPrimitiveType}}, {{/isBodyParam}} {{/allParams}} - }, + },{{/isMultipart}} } return z.request(options).then((response) => { response.throwForStatus(); diff --git a/modules/openapi-generator/src/main/resources/zapier/package.mustache b/modules/openapi-generator/src/main/resources/zapier/package.mustache index af565854aba6..95d261febc02 100644 --- a/modules/openapi-generator/src/main/resources/zapier/package.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/package.mustache @@ -13,7 +13,8 @@ }, "dependencies": { "lodash": "^4.17.21", - "zapier-platform-core": "14.1.1" + "zapier-platform-core": "14.1.1", + "form-data": "2.1.4" }, "devDependencies": { "mocha": "^10.2.0", diff --git a/samples/client/petstore/zapier/apis/PetApi.js b/samples/client/petstore/zapier/apis/PetApi.js index 791f60f53fe9..140002995c12 100644 --- a/samples/client/petstore/zapier/apis/PetApi.js +++ b/samples/client/petstore/zapier/apis/PetApi.js @@ -1,6 +1,7 @@ const ApiResponse = require('../models/ApiResponse'); const Pet = require('../models/Pet'); const utils = require('../utils/utils'); +const FormData = require('form-data'); module.exports = { addPet: { @@ -332,19 +333,22 @@ module.exports = { ...ApiResponse.fields('', false), ], perform: async (z, bundle) => { + const formData = new FormData() + formData.append('additionalMetadata', bundle.inputData?.['additionalMetadata']) + const filename = bundle.inputData?.['filename'] || bundle.inputData?.['file'].split('/').slice(-1)[0] + formData.append('file', (await (await z.request({url: bundle.inputData?.['file'], method: 'GET', raw: true})).buffer()), { filename: filename }) const options = { url: utils.replacePathParameters('http://petstore.swagger.io/v2/pet/{petId}/uploadImage'), method: 'POST', removeMissingValuesFrom: { params: true, body: true }, headers: { 'Authorization': 'Bearer {{bundle.authData.access_token}}', - 'Content-Type': 'multipart/form-data', + 'Accept': 'application/json', }, params: { }, - body: { - }, + body: formData, } return z.request(options).then((response) => { response.throwForStatus(); diff --git a/samples/client/petstore/zapier/package.json b/samples/client/petstore/zapier/package.json index 104976d509b7..f4d4102ceac1 100644 --- a/samples/client/petstore/zapier/package.json +++ b/samples/client/petstore/zapier/package.json @@ -13,7 +13,8 @@ }, "dependencies": { "lodash": "^4.17.21", - "zapier-platform-core": "14.1.1" + "zapier-platform-core": "14.1.1", + "form-data": "2.1.4" }, "devDependencies": { "mocha": "^10.2.0", From 4531b951272c9ab5c59323f054ffce07c87b11f0 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 3 Jul 2023 12:49:18 +0200 Subject: [PATCH 07/20] added samples generation --- .../languages/ZapierClientCodegen.java | 64 +++++++++++++++++-- .../src/main/resources/zapier/README.mustache | 0 .../src/main/resources/zapier/api.mustache | 6 +- .../src/main/resources/zapier/model.mustache | 16 ++--- .../src/main/resources/zapier/sample.mustache | 18 ++++++ .../petstore/zapier/.openapi-generator/FILES | 1 + samples/client/petstore/zapier/README.md | 0 samples/client/petstore/zapier/apis/PetApi.js | 25 +++++--- .../client/petstore/zapier/apis/StoreApi.js | 16 +++-- .../client/petstore/zapier/apis/UserApi.js | 27 +++++--- .../client/petstore/zapier/models/Order.js | 2 +- .../client/petstore/zapier/samples/PetApi.js | 14 ++++ .../petstore/zapier/samples/StoreApi.js | 6 ++ .../client/petstore/zapier/samples/UserApi.js | 4 ++ 14 files changed, 160 insertions(+), 39 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/zapier/README.mustache create mode 100644 modules/openapi-generator/src/main/resources/zapier/sample.mustache create mode 100644 samples/client/petstore/zapier/README.md create mode 100644 samples/client/petstore/zapier/samples/PetApi.js create mode 100644 samples/client/petstore/zapier/samples/StoreApi.js create mode 100644 samples/client/petstore/zapier/samples/UserApi.js diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java index 8cb58b580cf3..28a3641cf160 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java @@ -1,14 +1,17 @@ package org.openapitools.codegen.languages; +import com.fasterxml.jackson.core.JsonProcessingException; +import io.swagger.v3.core.util.Json; +import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.responses.ApiResponse; import org.openapitools.codegen.*; +import org.openapitools.codegen.utils.ModelUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; +import java.util.*; import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; import static org.openapitools.codegen.utils.StringUtils.camelize; @@ -39,16 +42,19 @@ public ZapierClientCodegen() { apiTemplateFiles.put("api.mustache", ".js"); embeddedTemplateDir = templateDir = "zapier"; apiPackage = "apis"; + testPackage = "samples"; modelPackage = "models"; + apiTestTemplateFiles.put("sample.mustache", ".js"); supportingFiles.add(new SupportingFile("actions.mustache", "operations", "actions.js")); supportingFiles.add(new SupportingFile("utils.mustache", "utils", "utils.js")); supportingFiles.add(new SupportingFile("index.mustache", "", "index.js")); supportingFiles.add(new SupportingFile("authentication.mustache", "", "authentication.js")); supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); languageSpecificPrimitives.clear(); languageSpecificPrimitives = new HashSet<>( - Arrays.asList("number", "integer", "string", "boolean", "array", "file") + Arrays.asList("number", "integer", "string", "boolean", "array", "file", "object") ); instantiationTypes.put("array", "array"); @@ -80,6 +86,12 @@ public ZapierClientCodegen() { typeMapping.put("URI", "string"); } + @Override + protected void initializeSpecialCharacterMapping() { + super.initializeSpecialCharacterMapping(); + specialCharReplacements.remove("_"); + } + /** * Works identically to {@link DefaultCodegen#toParamName(String)} but doesn't camelize. * @@ -129,6 +141,11 @@ public String toModelFilename(String name) { return name; } + @Override + public String toApiTestFilename(String name) { + return toApiName(name); + } + @Override public GeneratorLanguage generatorLanguage() { return null; } @@ -143,4 +160,43 @@ public String escapeQuotationMark(String input) { // do nothing as the output is just doc return input; } + + @Override + public CodegenResponse fromResponse(String responseCode, ApiResponse response) { + CodegenResponse r = super.fromResponse(responseCode, response); + try { + Map>> map = Json.mapper().readerFor(Map.class).readValue(Json.pretty(response.getContent())); + Map.Entry>> entry = map.entrySet().stream().findFirst().get(); + Map> example = entry.getValue(); + List> ex = toExamples(example.get("examples")); + r.examples = toExamples(example.get("examples")); + } catch (Exception e) { + LOGGER.error(e.toString()); + } + return r; + } + + @Override + protected List> toExamples(Map examples) { + if (examples == null) { + return null; + } + + final List> output = new ArrayList<>(examples.size()); + for (Map.Entry entry : examples.entrySet()) { + final Map kv = new HashMap<>(); + @SuppressWarnings("unchecked") + Map map = (Map) entry.getValue(); + String example = ""; + try{ + example = Json.mapper().writeValueAsString(map.getOrDefault("value", map)); + } catch(Exception e) {} + + kv.put("example", example); + output.add(kv); + } + + return output; + } + } diff --git a/modules/openapi-generator/src/main/resources/zapier/README.mustache b/modules/openapi-generator/src/main/resources/zapier/README.mustache new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/modules/openapi-generator/src/main/resources/zapier/api.mustache b/modules/openapi-generator/src/main/resources/zapier/api.mustache index fea0f8efd49a..b3a940274ea2 100644 --- a/modules/openapi-generator/src/main/resources/zapier/api.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/api.mustache @@ -1,3 +1,4 @@ +const samples = require('../samples/{{classFilename}}'); {{#imports}}{{{import}}} {{/imports}} const utils = require('../utils/utils'); @@ -94,9 +95,10 @@ module.exports = { return z.request(options).then((response) => { response.throwForStatus(); const results = response.json; - return results; + return {{#returnType}}{{#returnTypeIsPrimitive}}{ data: results }{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}results{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}results{{/returnType}}; }) - } + }, + sample: {{#returnType}}{{^returnTypeIsPrimitive}}{{#responses}}{{#baseType}}samples['{{baseType}}Sample']{{/baseType}}{{/responses}}{{/returnTypeIsPrimitive}}{{#returnTypeIsPrimitive}}{ data: {} }{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}{ data: {} }{{/returnType}} } }, {{/operation}} diff --git a/modules/openapi-generator/src/main/resources/zapier/model.mustache b/modules/openapi-generator/src/main/resources/zapier/model.mustache index 97b345026734..cee4eca880b3 100644 --- a/modules/openapi-generator/src/main/resources/zapier/model.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/model.mustache @@ -37,7 +37,12 @@ module.exports = { type: '{{#items}}{{baseType}}{{/items}}', {{/isArray}} {{^isArray}} - type: '{{#isInteger}}integer{{/isInteger}}{{^isInteger}}{{#isNumeric}}number{{/isNumeric}}{{/isInteger}}{{#isString}}string{{/isString}}{{#isBoolean}}boolean{{/isBoolean}}{{#isDateTime}}datetime{{/isDateTime}}{{#isDate}}datetime{{/isDate}}{{#isFile}}file{{/isFile}}', + {{#isFreeFormObject}} + dict: true, + {{/isFreeFormObject}} + {{^isFreeFormObject}} + type: '{{baseType}}', + {{/isFreeFormObject}} {{/isArray}} {{#isEnum}} choices: [ @@ -61,13 +66,6 @@ module.exports = { {{/isArray}} {{^isArray}} {{^allowableValues}} - {{#isFreeFormObject}} - { - key: `${keyPrefix}{{baseName}}`, - label: `{{#description}}{{{.}}} - {{/description}}[${labelPrefix}{{baseName}}]`, - dict: true, - }, - {{/isFreeFormObject}} {{^isFreeFormObject}} ...{{complexType}}.fields(`${keyPrefix}{{baseName}}`, isInput), {{/isFreeFormObject}} @@ -87,7 +85,7 @@ module.exports = { let keyPrefix = prefix && `${prefix}.` return { {{#vars}} - '{{baseName}}': {{#isPrimitiveType}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/isPrimitiveType}}{{^isPrimitiveType}}{{^allowableValues}}{{^isArray}}{{#isFreeFormObject}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/isFreeFormObject}}{{^isFreeFormObject}}utils.removeIfEmpty({{complexType}}.mapping(bundle, `${keyPrefix}{{baseName}}`)){{/isFreeFormObject}}{{/isArray}}{{#isArray}}utils.removeKeyPrefixes(bundle.inputData?.[`${keyPrefix}{{baseName}}`]){{/isArray}}{{/allowableValues}}{{#allowableValues}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/allowableValues}}{{/isPrimitiveType}}, + '{{baseName}}': {{#isPrimitiveType}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/isPrimitiveType}}{{^isPrimitiveType}}{{^allowableValues}}{{^isArray}}utils.removeIfEmpty({{complexType}}.mapping(bundle, `${keyPrefix}{{baseName}}`)){{/isArray}}{{#isArray}}utils.removeKeyPrefixes(bundle.inputData?.[`${keyPrefix}{{baseName}}`]){{/isArray}}{{/allowableValues}}{{#allowableValues}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/allowableValues}}{{/isPrimitiveType}}, {{/vars}} } }, diff --git a/modules/openapi-generator/src/main/resources/zapier/sample.mustache b/modules/openapi-generator/src/main/resources/zapier/sample.mustache new file mode 100644 index 000000000000..26d10c5b085d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/zapier/sample.mustache @@ -0,0 +1,18 @@ +{{#operations}} +module.export = { +{{#operation}} +{{#returnType}} +{{^returnTypeIsPrimitive}} +{{#responses}} +{{#is2xx}} + {{#baseType}} + "{{baseType}}Sample": + {{#examples}}{{#-last}}{{{example}}}{{/-last}}{{/examples}}{{^examples}}{ data: {} }{{/examples}}, + {{/baseType}} +{{/is2xx}} +{{/responses}} +{{/returnTypeIsPrimitive}} +{{/returnType}} +{{/operation}} +} +{{/operations}} diff --git a/samples/client/petstore/zapier/.openapi-generator/FILES b/samples/client/petstore/zapier/.openapi-generator/FILES index 29a34b32c746..2dcb04d6086c 100644 --- a/samples/client/petstore/zapier/.openapi-generator/FILES +++ b/samples/client/petstore/zapier/.openapi-generator/FILES @@ -1,3 +1,4 @@ +README.md apis/PetApi.js apis/StoreApi.js apis/UserApi.js diff --git a/samples/client/petstore/zapier/README.md b/samples/client/petstore/zapier/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/samples/client/petstore/zapier/apis/PetApi.js b/samples/client/petstore/zapier/apis/PetApi.js index 140002995c12..473dcea31c11 100644 --- a/samples/client/petstore/zapier/apis/PetApi.js +++ b/samples/client/petstore/zapier/apis/PetApi.js @@ -1,3 +1,4 @@ +const samples = require('../samples/PetApi'); const ApiResponse = require('../models/ApiResponse'); const Pet = require('../models/Pet'); const utils = require('../utils/utils'); @@ -40,7 +41,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: samples['PetSample'] } }, deletePet: { @@ -87,7 +89,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: { data: {} } } }, findPetsByStatus: { @@ -126,7 +129,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: samples['PetSample'] } }, findPetsByTags: { @@ -165,7 +169,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: samples['PetSample'] } }, getPetById: { @@ -208,7 +213,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: samples['PetSample'] } }, updatePet: { @@ -247,7 +253,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: samples['PetSample'] } }, updatePetWithForm: { @@ -299,7 +306,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: { data: {} } } }, uploadFile: { @@ -355,7 +363,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: samples['ApiResponseSample'] } }, } diff --git a/samples/client/petstore/zapier/apis/StoreApi.js b/samples/client/petstore/zapier/apis/StoreApi.js index 2ef67344374b..0292fa8fb3b3 100644 --- a/samples/client/petstore/zapier/apis/StoreApi.js +++ b/samples/client/petstore/zapier/apis/StoreApi.js @@ -1,5 +1,5 @@ +const samples = require('../samples/StoreApi'); const Order = require('../models/Order'); -const object = require('../models/object'); const utils = require('../utils/utils'); module.exports = { @@ -42,7 +42,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: { data: {} } } }, getInventory: { @@ -76,9 +77,10 @@ module.exports = { return z.request(options).then((response) => { response.throwForStatus(); const results = response.json; - return results; + return { data: results }; }) - } + }, + sample: { data: {} } } }, getOrderById: { @@ -121,7 +123,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: samples['OrderSample'] } }, placeOrder: { @@ -160,7 +163,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: samples['OrderSample'] } }, } diff --git a/samples/client/petstore/zapier/apis/UserApi.js b/samples/client/petstore/zapier/apis/UserApi.js index 0419332bbdde..47b16423539a 100644 --- a/samples/client/petstore/zapier/apis/UserApi.js +++ b/samples/client/petstore/zapier/apis/UserApi.js @@ -1,3 +1,4 @@ +const samples = require('../samples/UserApi'); const User = require('../models/User'); const utils = require('../utils/utils'); @@ -37,7 +38,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: { data: {} } } }, createUsersWithArrayInput: { @@ -75,7 +77,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: { data: {} } } }, createUsersWithListInput: { @@ -113,7 +116,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: { data: {} } } }, deleteUser: { @@ -155,7 +159,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: { data: {} } } }, getUserByName: { @@ -198,7 +203,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: samples['UserSample'] } }, loginUser: { @@ -246,9 +252,10 @@ module.exports = { return z.request(options).then((response) => { response.throwForStatus(); const results = response.json; - return results; + return { data: results }; }) - } + }, + sample: { data: {} } } }, logoutUser: { @@ -284,7 +291,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: { data: {} } } }, updateUser: { @@ -328,7 +336,8 @@ module.exports = { const results = response.json; return results; }) - } + }, + sample: { data: {} } } }, } diff --git a/samples/client/petstore/zapier/models/Order.js b/samples/client/petstore/zapier/models/Order.js index 764b03bc7ea9..59b30fcb93d1 100644 --- a/samples/client/petstore/zapier/models/Order.js +++ b/samples/client/petstore/zapier/models/Order.js @@ -24,7 +24,7 @@ module.exports = { { key: `${keyPrefix}shipDate`, label: `[${labelPrefix}shipDate]`, - type: 'datetime', + type: 'string', }, { key: `${keyPrefix}status`, diff --git a/samples/client/petstore/zapier/samples/PetApi.js b/samples/client/petstore/zapier/samples/PetApi.js new file mode 100644 index 000000000000..3ef6e6adfab1 --- /dev/null +++ b/samples/client/petstore/zapier/samples/PetApi.js @@ -0,0 +1,14 @@ +module.export = { + "PetSample": + { data: {} }, + "PetSample": + { data: {} }, + "PetSample": + { data: {} }, + "PetSample": + { data: {} }, + "PetSample": + { data: {} }, + "ApiResponseSample": + { data: {} }, +} diff --git a/samples/client/petstore/zapier/samples/StoreApi.js b/samples/client/petstore/zapier/samples/StoreApi.js new file mode 100644 index 000000000000..c948e814e305 --- /dev/null +++ b/samples/client/petstore/zapier/samples/StoreApi.js @@ -0,0 +1,6 @@ +module.export = { + "OrderSample": + { data: {} }, + "OrderSample": + { data: {} }, +} diff --git a/samples/client/petstore/zapier/samples/UserApi.js b/samples/client/petstore/zapier/samples/UserApi.js new file mode 100644 index 000000000000..8053c81b88d5 --- /dev/null +++ b/samples/client/petstore/zapier/samples/UserApi.js @@ -0,0 +1,4 @@ +module.export = { + "UserSample": + { data: {} }, +} From 0e4ec16d27f6952b42ff402c9894d92bf822044f Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 3 Jul 2023 14:12:33 +0200 Subject: [PATCH 08/20] updated docs --- docs/generators/zapier.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/generators/zapier.md b/docs/generators/zapier.md index c932be7e2d32..f054dcd0a6c2 100644 --- a/docs/generators/zapier.md +++ b/docs/generators/zapier.md @@ -50,6 +50,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • file
  • integer
  • number
  • +
  • object
  • string
  • From fe62f7bf9707df01022f20685665b827fb72a0f2 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 3 Jul 2023 14:45:39 +0200 Subject: [PATCH 09/20] fixed zapier api template --- .../openapi-generator/src/main/resources/zapier/api.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/resources/zapier/api.mustache b/modules/openapi-generator/src/main/resources/zapier/api.mustache index b3a940274ea2..8c1c7d5e34d4 100644 --- a/modules/openapi-generator/src/main/resources/zapier/api.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/api.mustache @@ -98,7 +98,7 @@ module.exports = { return {{#returnType}}{{#returnTypeIsPrimitive}}{ data: results }{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}results{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}results{{/returnType}}; }) }, - sample: {{#returnType}}{{^returnTypeIsPrimitive}}{{#responses}}{{#baseType}}samples['{{baseType}}Sample']{{/baseType}}{{/responses}}{{/returnTypeIsPrimitive}}{{#returnTypeIsPrimitive}}{ data: {} }{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}{ data: {} }{{/returnType}} + sample: {{#returnType}}{{^returnTypeIsPrimitive}}{{#responses}}{{#is2xx}}{{#baseType}}samples['{{baseType}}Sample']{{/baseType}}{{/is2xx}}{{/responses}}{{/returnTypeIsPrimitive}}{{#returnTypeIsPrimitive}}{ data: {} }{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}{ data: {} }{{/returnType}} } }, {{/operation}} From 625f1380734f33835947baf333f53d852fa033dc Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 3 Jul 2023 14:50:55 +0200 Subject: [PATCH 10/20] fixed zapier samples export --- .../openapi-generator/src/main/resources/zapier/sample.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/resources/zapier/sample.mustache b/modules/openapi-generator/src/main/resources/zapier/sample.mustache index 26d10c5b085d..a7f3757c38c4 100644 --- a/modules/openapi-generator/src/main/resources/zapier/sample.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/sample.mustache @@ -1,5 +1,5 @@ {{#operations}} -module.export = { +module.exports = { {{#operation}} {{#returnType}} {{^returnTypeIsPrimitive}} From 3a11efa979db27b4cb639e6e17cb0deb93510be1 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 3 Jul 2023 16:42:35 +0200 Subject: [PATCH 11/20] added zapier readme template --- .../src/main/resources/zapier/README.mustache | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/modules/openapi-generator/src/main/resources/zapier/README.mustache b/modules/openapi-generator/src/main/resources/zapier/README.mustache index e69de29bb2d1..6627e6e0aa18 100644 --- a/modules/openapi-generator/src/main/resources/zapier/README.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/README.mustache @@ -0,0 +1,51 @@ +# Documentation for zapier generator + +This generator generates a partial implementation of a zapier integration from an openapi specification. + +## Why is it partial? + +It's a partial integration because you have to put in some code for it to be 100% complete, code that depends only on how your api is structured. + +Here there are all the parts you need to complete by yourself: + +### 1) **utils/utils.js** isSearchAction method +This method has to return either true or false if a method is a [zapier search action](https://platform.zapier.com/docs/search-create). +``` +const isSearchAction = (key) => { + // TODO: custom logic + return false +} +``` + +### 2) **utils/utils.js** searchMiddleware method +This method has to return an array of resources (searches must return an array), if you have pagination or you api returns an array inside nested fields, here you have to extract the array. + +``` +const searchMiddleware = (action) => { + // TODO: custom logic + return action +} +``` + +### 3) **authentication.js** +This file must be written completely according to your api authentication, you can get it generated automatically by creating the integration on the zapier website and filling the requested data, or you can build it yourself following [this guide](https://platform.zapier.com/cli_tutorials/getting-started#adding-authentication). + +## Samples +To get your app made public on zapier you must provide a sample (json example response) for each of your actions, these samples get automatically generated by this generator but you have to have actual response examples in you openapi file. + +For example: + +``` +CreateUserResponse: + description: Example response + content: + application/json: + schema: + $ref: ./models/responses/CreateUserResponse.yaml + examples: + example-1: + value: + data: + id: 12345 + name: user1 +``` \ No newline at end of file From 380075d3e0cdbd494cd8bb0bb48d7527a015be03 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Mon, 3 Jul 2023 16:57:26 +0200 Subject: [PATCH 12/20] fixed zapier readme template --- .../openapi-generator/src/main/resources/zapier/README.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/resources/zapier/README.mustache b/modules/openapi-generator/src/main/resources/zapier/README.mustache index 6627e6e0aa18..d12e0e96be25 100644 --- a/modules/openapi-generator/src/main/resources/zapier/README.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/README.mustache @@ -48,4 +48,4 @@ CreateUserResponse: data: id: 12345 name: user1 -``` \ No newline at end of file +``` From 15b67fe20ff77a64f4bafa2b2093800614c86007 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Tue, 4 Jul 2023 09:21:57 +0200 Subject: [PATCH 13/20] added petstore readme --- samples/client/petstore/zapier/README.md | 51 ++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/samples/client/petstore/zapier/README.md b/samples/client/petstore/zapier/README.md index e69de29bb2d1..d12e0e96be25 100644 --- a/samples/client/petstore/zapier/README.md +++ b/samples/client/petstore/zapier/README.md @@ -0,0 +1,51 @@ +# Documentation for zapier generator + +This generator generates a partial implementation of a zapier integration from an openapi specification. + +## Why is it partial? + +It's a partial integration because you have to put in some code for it to be 100% complete, code that depends only on how your api is structured. + +Here there are all the parts you need to complete by yourself: + +### 1) **utils/utils.js** isSearchAction method +This method has to return either true or false if a method is a [zapier search action](https://platform.zapier.com/docs/search-create). +``` +const isSearchAction = (key) => { + // TODO: custom logic + return false +} +``` + +### 2) **utils/utils.js** searchMiddleware method +This method has to return an array of resources (searches must return an array), if you have pagination or you api returns an array inside nested fields, here you have to extract the array. + +``` +const searchMiddleware = (action) => { + // TODO: custom logic + return action +} +``` + +### 3) **authentication.js** +This file must be written completely according to your api authentication, you can get it generated automatically by creating the integration on the zapier website and filling the requested data, or you can build it yourself following [this guide](https://platform.zapier.com/cli_tutorials/getting-started#adding-authentication). + +## Samples +To get your app made public on zapier you must provide a sample (json example response) for each of your actions, these samples get automatically generated by this generator but you have to have actual response examples in you openapi file. + +For example: + +``` +CreateUserResponse: + description: Example response + content: + application/json: + schema: + $ref: ./models/responses/CreateUserResponse.yaml + examples: + example-1: + value: + data: + id: 12345 + name: user1 +``` From e0ef68a8d206d03a945b1b74bf959b98f3ae7c96 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Tue, 4 Jul 2023 09:46:02 +0200 Subject: [PATCH 14/20] cleaned zapier generator --- .../openapitools/codegen/languages/ZapierClientCodegen.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java index 28a3641cf160..52bb93222e28 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java @@ -151,13 +151,11 @@ public String toApiTestFilename(String name) { @Override public String escapeUnsafeCharacters(String input) { - // do nothing as the output is just doc return input; } @Override public String escapeQuotationMark(String input) { - // do nothing as the output is just doc return input; } @@ -168,7 +166,6 @@ public CodegenResponse fromResponse(String responseCode, ApiResponse response) { Map>> map = Json.mapper().readerFor(Map.class).readValue(Json.pretty(response.getContent())); Map.Entry>> entry = map.entrySet().stream().findFirst().get(); Map> example = entry.getValue(); - List> ex = toExamples(example.get("examples")); r.examples = toExamples(example.get("examples")); } catch (Exception e) { LOGGER.error(e.toString()); @@ -190,7 +187,7 @@ protected List> toExamples(Map examples) { String example = ""; try{ example = Json.mapper().writeValueAsString(map.getOrDefault("value", map)); - } catch(Exception e) {} + } catch(Exception ignored) {} kv.put("example", example); output.add(kv); From 548a48bb7d6c0eb9c825c3be1bd0eeb6b04972b5 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Tue, 4 Jul 2023 09:56:16 +0200 Subject: [PATCH 15/20] updated samples --- .../src/Org.OpenAPITools/Api/FakeApi.cs | 20 +++++++++---------- .../src/Org.OpenAPITools/Api/FakeApi.cs | 16 +++++++-------- .../src/Org.OpenAPITools/Api/FakeApi.cs | 16 +++++++-------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/samples/client/petstore/csharp/OpenAPIClient-generichost-net6.0-nrt/src/Org.OpenAPITools/Api/FakeApi.cs b/samples/client/petstore/csharp/OpenAPIClient-generichost-net6.0-nrt/src/Org.OpenAPITools/Api/FakeApi.cs index 38734e5b35cf..6ffeef01e096 100644 --- a/samples/client/petstore/csharp/OpenAPIClient-generichost-net6.0-nrt/src/Org.OpenAPITools/Api/FakeApi.cs +++ b/samples/client/petstore/csharp/OpenAPIClient-generichost-net6.0-nrt/src/Org.OpenAPITools/Api/FakeApi.cs @@ -2023,15 +2023,18 @@ public async Task> TestEndpointParametersAsync(byte[] varByt /// /// Validates the request parameters /// + /// /// /// /// - /// - /// /// + /// /// - private void ValidateTestEnumParameters(Option> enumHeaderStringArray, Option> enumQueryStringArray, Option> enumFormStringArray, Option enumQueryString, Option enumHeaderString, Option enumFormString) + private void ValidateTestEnumParameters(Option enumHeaderString, Option> enumHeaderStringArray, Option> enumQueryStringArray, Option> enumFormStringArray, Option enumFormString, Option enumQueryString) { + if (enumHeaderString.IsSet && enumHeaderString.Value == null) + throw new ArgumentNullException(nameof(enumHeaderString)); + if (enumHeaderStringArray.IsSet && enumHeaderStringArray.Value == null) throw new ArgumentNullException(nameof(enumHeaderStringArray)); @@ -2041,14 +2044,11 @@ private void ValidateTestEnumParameters(Option> enumHeaderStringArr if (enumFormStringArray.IsSet && enumFormStringArray.Value == null) throw new ArgumentNullException(nameof(enumFormStringArray)); - if (enumQueryString.IsSet && enumQueryString.Value == null) - throw new ArgumentNullException(nameof(enumQueryString)); - - if (enumHeaderString.IsSet && enumHeaderString.Value == null) - throw new ArgumentNullException(nameof(enumHeaderString)); - if (enumFormString.IsSet && enumFormString.Value == null) throw new ArgumentNullException(nameof(enumFormString)); + + if (enumQueryString.IsSet && enumQueryString.Value == null) + throw new ArgumentNullException(nameof(enumQueryString)); } /// @@ -2167,7 +2167,7 @@ public async Task> TestEnumParametersAsync(Option> TestEndpointParametersAsync(byte[] varByt /// /// /// - /// + /// /// /// - /// + /// /// - private void ValidateTestEnumParameters(Option> enumQueryStringArray, Option> enumFormStringArray, Option enumQueryString, Option> enumHeaderStringArray, Option enumFormString, Option enumHeaderString) + private void ValidateTestEnumParameters(Option> enumQueryStringArray, Option> enumFormStringArray, Option enumHeaderString, Option> enumHeaderStringArray, Option enumFormString, Option enumQueryString) { if (enumQueryStringArray.IsSet && enumQueryStringArray.Value == null) throw new ArgumentNullException(nameof(enumQueryStringArray)); @@ -2036,8 +2036,8 @@ private void ValidateTestEnumParameters(Option> enumQueryStringArra if (enumFormStringArray.IsSet && enumFormStringArray.Value == null) throw new ArgumentNullException(nameof(enumFormStringArray)); - if (enumQueryString.IsSet && enumQueryString.Value == null) - throw new ArgumentNullException(nameof(enumQueryString)); + if (enumHeaderString.IsSet && enumHeaderString.Value == null) + throw new ArgumentNullException(nameof(enumHeaderString)); if (enumHeaderStringArray.IsSet && enumHeaderStringArray.Value == null) throw new ArgumentNullException(nameof(enumHeaderStringArray)); @@ -2045,8 +2045,8 @@ private void ValidateTestEnumParameters(Option> enumQueryStringArra if (enumFormString.IsSet && enumFormString.Value == null) throw new ArgumentNullException(nameof(enumFormString)); - if (enumHeaderString.IsSet && enumHeaderString.Value == null) - throw new ArgumentNullException(nameof(enumHeaderString)); + if (enumQueryString.IsSet && enumQueryString.Value == null) + throw new ArgumentNullException(nameof(enumQueryString)); } /// @@ -2165,7 +2165,7 @@ public async Task> TestEnumParametersAsync(Option> TestEndpointParametersAsync(byte[] varByt /// /// /// - /// + /// /// /// - /// + /// /// - private void ValidateTestEnumParameters(Option> enumQueryStringArray, Option> enumFormStringArray, Option enumQueryString, Option> enumHeaderStringArray, Option enumFormString, Option enumHeaderString) + private void ValidateTestEnumParameters(Option> enumQueryStringArray, Option> enumFormStringArray, Option enumHeaderString, Option> enumHeaderStringArray, Option enumFormString, Option enumQueryString) { if (enumQueryStringArray.IsSet && enumQueryStringArray.Value == null) throw new ArgumentNullException(nameof(enumQueryStringArray)); @@ -2029,8 +2029,8 @@ private void ValidateTestEnumParameters(Option> enumQueryStringArra if (enumFormStringArray.IsSet && enumFormStringArray.Value == null) throw new ArgumentNullException(nameof(enumFormStringArray)); - if (enumQueryString.IsSet && enumQueryString.Value == null) - throw new ArgumentNullException(nameof(enumQueryString)); + if (enumHeaderString.IsSet && enumHeaderString.Value == null) + throw new ArgumentNullException(nameof(enumHeaderString)); if (enumHeaderStringArray.IsSet && enumHeaderStringArray.Value == null) throw new ArgumentNullException(nameof(enumHeaderStringArray)); @@ -2038,8 +2038,8 @@ private void ValidateTestEnumParameters(Option> enumQueryStringArra if (enumFormString.IsSet && enumFormString.Value == null) throw new ArgumentNullException(nameof(enumFormString)); - if (enumHeaderString.IsSet && enumHeaderString.Value == null) - throw new ArgumentNullException(nameof(enumHeaderString)); + if (enumQueryString.IsSet && enumQueryString.Value == null) + throw new ArgumentNullException(nameof(enumQueryString)); } /// @@ -2158,7 +2158,7 @@ public async Task> TestEnumParametersAsync(Option Date: Tue, 4 Jul 2023 10:56:38 +0200 Subject: [PATCH 16/20] fixed zapier enum label --- .../openapi-generator/src/main/resources/zapier/model.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/resources/zapier/model.mustache b/modules/openapi-generator/src/main/resources/zapier/model.mustache index cee4eca880b3..f3f84620c735 100644 --- a/modules/openapi-generator/src/main/resources/zapier/model.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/model.mustache @@ -9,7 +9,7 @@ const utils = require('../utils/utils'); module.exports = { fields: (key) => ( { - label: `{{#description}}{{{.}}} - {{/description}}[${key}]`, + label: `{{#description}}{{{.}}} - {{/description}}[${key.replaceAll('__', '.')}]`, choices: [ {{#allowableValues}} {{#values}} From 5f4eccde571d2db6e24154c24ca33a6119e601b7 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Wed, 5 Jul 2023 09:53:33 +0200 Subject: [PATCH 17/20] cleaned code --- .../src/main/resources/zapier/model.mustache | 10 ++++------ .../src/main/resources/zapier/utils.mustache | 9 +++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/zapier/model.mustache b/modules/openapi-generator/src/main/resources/zapier/model.mustache index f3f84620c735..fd27ed85584b 100644 --- a/modules/openapi-generator/src/main/resources/zapier/model.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/model.mustache @@ -1,4 +1,3 @@ -const _ = require('lodash') const utils = require('../utils/utils'); {{#imports}}{{{import}}} {{/imports}} @@ -23,9 +22,8 @@ module.exports = { {{/isEnum}} {{^isEnum}} module.exports = { - fields: (prefix = '', isInput = true) => { - let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` - let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + fields: (prefix = '', isInput = true, isArrayChild = false) => { + const {keyPrefix, labelPrefix} = utils.buildKeyAndLabel(prefix, isInput, isArrayChild) return [ {{#vars}} {{#isPrimitiveType}} @@ -58,7 +56,7 @@ module.exports = { { key: `${keyPrefix}{{baseName}}`,{{#items}}{{^isEnumRef}} label: `{{#description}}{{{.}}} - {{/description}}[${labelPrefix}{{baseName}}]`, - children: {{complexType}}.fields(`${keyPrefix}{{baseName}}${!isInput && '[]'}`), {{/isEnumRef}}{{#isEnumRef}} + children: {{complexType}}.fields(`${keyPrefix}{{baseName}}${!isInput ? '[]' : ''}`, isInput, true), {{/isEnumRef}}{{#isEnumRef}} list: true, type: 'string', ...{{complexType}}.fields(`${keyPrefix}{{baseName}}`, isInput),{{/isEnumRef}}{{/items}} @@ -82,7 +80,7 @@ module.exports = { ] }, mapping: (bundle, prefix = '') => { - let keyPrefix = prefix && `${prefix}.` + const {keyPrefix} = utils.buildKeyAndLabel(prefix) return { {{#vars}} '{{baseName}}': {{#isPrimitiveType}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/isPrimitiveType}}{{^isPrimitiveType}}{{^allowableValues}}{{^isArray}}utils.removeIfEmpty({{complexType}}.mapping(bundle, `${keyPrefix}{{baseName}}`)){{/isArray}}{{#isArray}}utils.removeKeyPrefixes(bundle.inputData?.[`${keyPrefix}{{baseName}}`]){{/isArray}}{{/allowableValues}}{{#allowableValues}}bundle.inputData?.[`${keyPrefix}{{baseName}}`]{{/allowableValues}}{{/isPrimitiveType}}, diff --git a/modules/openapi-generator/src/main/resources/zapier/utils.mustache b/modules/openapi-generator/src/main/resources/zapier/utils.mustache index cfc027c9ad24..6d49446a60d8 100644 --- a/modules/openapi-generator/src/main/resources/zapier/utils.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/utils.mustache @@ -3,6 +3,14 @@ const _ = require('lodash') const replacePathParameters = (url) => url.replace(/{([^{}]+)}/g, (keyExpr, key) => `{{bundle.inputData.${key}}}`) const removeKeyPrefixes = (objectsArray) => objectsArray == undefined || typeof objectsArray[0] != 'object' ? objectsArray : objectsArray.map((obj) => Object.keys(obj).reduce((res, key) => (res[(key.split('.')).slice(-1)] = obj[key], res), {})) const removeIfEmpty = (obj) => _.isEmpty(JSON.parse(JSON.stringify(obj))) ? undefined : obj +const buildKeyAndLabel = (prefix, isInput = true, isArrayChild = false) => { + const keyPrefix = !_.isEmpty(prefix) && (!isArrayChild || isInput) ? `${prefix}${isInput ? '.' : '__'}` : prefix + const labelPrefix = !_.isEmpty(keyPrefix) ? keyPrefix.replaceAll('__', '.') : '' + return { + keyPrefix: keyPrefix, + labelPrefix:labelPrefix, + } +} const hasASearchField = action => action.operation.inputFields.length > 0 const isSearchAction = (key) => { // TODO: custom logic @@ -17,6 +25,7 @@ module.exports = { replacePathParameters: replacePathParameters, removeKeyPrefixes: removeKeyPrefixes, removeIfEmpty: removeIfEmpty, + buildKeyAndLabel: buildKeyAndLabel, hasASearchField: hasASearchField, isSearchAction: isSearchAction, searchMiddleware: searchMiddleware, From 0ace14b617cf0691d7b2f919bb043ac977101ab0 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Wed, 5 Jul 2023 09:59:38 +0200 Subject: [PATCH 18/20] updated samples --- samples/client/petstore/zapier/models/ApiResponse.js | 8 +++----- samples/client/petstore/zapier/models/Category.js | 8 +++----- samples/client/petstore/zapier/models/Order.js | 8 +++----- samples/client/petstore/zapier/models/Pet.js | 10 ++++------ samples/client/petstore/zapier/models/Tag.js | 8 +++----- samples/client/petstore/zapier/models/User.js | 8 +++----- samples/client/petstore/zapier/utils/utils.js | 9 +++++++++ 7 files changed, 28 insertions(+), 31 deletions(-) diff --git a/samples/client/petstore/zapier/models/ApiResponse.js b/samples/client/petstore/zapier/models/ApiResponse.js index f5e2f01e41ac..c5bd2eba6971 100644 --- a/samples/client/petstore/zapier/models/ApiResponse.js +++ b/samples/client/petstore/zapier/models/ApiResponse.js @@ -1,10 +1,8 @@ -const _ = require('lodash') const utils = require('../utils/utils'); module.exports = { - fields: (prefix = '', isInput = true) => { - let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` - let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + fields: (prefix = '', isInput = true, isArrayChild = false) => { + const {keyPrefix, labelPrefix} = utils.buildKeyAndLabel(prefix, isInput, isArrayChild) return [ { key: `${keyPrefix}code`, @@ -24,7 +22,7 @@ module.exports = { ] }, mapping: (bundle, prefix = '') => { - let keyPrefix = prefix && `${prefix}.` + const {keyPrefix} = utils.buildKeyAndLabel(prefix) return { 'code': bundle.inputData?.[`${keyPrefix}code`], 'type': bundle.inputData?.[`${keyPrefix}type`], diff --git a/samples/client/petstore/zapier/models/Category.js b/samples/client/petstore/zapier/models/Category.js index ce2097ffed05..1c543e14767f 100644 --- a/samples/client/petstore/zapier/models/Category.js +++ b/samples/client/petstore/zapier/models/Category.js @@ -1,10 +1,8 @@ -const _ = require('lodash') const utils = require('../utils/utils'); module.exports = { - fields: (prefix = '', isInput = true) => { - let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` - let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + fields: (prefix = '', isInput = true, isArrayChild = false) => { + const {keyPrefix, labelPrefix} = utils.buildKeyAndLabel(prefix, isInput, isArrayChild) return [ { key: `${keyPrefix}id`, @@ -19,7 +17,7 @@ module.exports = { ] }, mapping: (bundle, prefix = '') => { - let keyPrefix = prefix && `${prefix}.` + const {keyPrefix} = utils.buildKeyAndLabel(prefix) return { 'id': bundle.inputData?.[`${keyPrefix}id`], 'name': bundle.inputData?.[`${keyPrefix}name`], diff --git a/samples/client/petstore/zapier/models/Order.js b/samples/client/petstore/zapier/models/Order.js index 59b30fcb93d1..d8478ef9004d 100644 --- a/samples/client/petstore/zapier/models/Order.js +++ b/samples/client/petstore/zapier/models/Order.js @@ -1,10 +1,8 @@ -const _ = require('lodash') const utils = require('../utils/utils'); module.exports = { - fields: (prefix = '', isInput = true) => { - let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` - let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + fields: (prefix = '', isInput = true, isArrayChild = false) => { + const {keyPrefix, labelPrefix} = utils.buildKeyAndLabel(prefix, isInput, isArrayChild) return [ { key: `${keyPrefix}id`, @@ -44,7 +42,7 @@ module.exports = { ] }, mapping: (bundle, prefix = '') => { - let keyPrefix = prefix && `${prefix}.` + const {keyPrefix} = utils.buildKeyAndLabel(prefix) return { 'id': bundle.inputData?.[`${keyPrefix}id`], 'petId': bundle.inputData?.[`${keyPrefix}petId`], diff --git a/samples/client/petstore/zapier/models/Pet.js b/samples/client/petstore/zapier/models/Pet.js index fceb76c03257..b0aa8bceec43 100644 --- a/samples/client/petstore/zapier/models/Pet.js +++ b/samples/client/petstore/zapier/models/Pet.js @@ -1,12 +1,10 @@ -const _ = require('lodash') const utils = require('../utils/utils'); const Category = require('../models/Category'); const Tag = require('../models/Tag'); module.exports = { - fields: (prefix = '', isInput = true) => { - let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` - let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + fields: (prefix = '', isInput = true, isArrayChild = false) => { + const {keyPrefix, labelPrefix} = utils.buildKeyAndLabel(prefix, isInput, isArrayChild) return [ { key: `${keyPrefix}id`, @@ -28,7 +26,7 @@ module.exports = { { key: `${keyPrefix}tags`, label: `[${labelPrefix}tags]`, - children: Tag.fields(`${keyPrefix}tags${!isInput && '[]'}`), + children: Tag.fields(`${keyPrefix}tags${!isInput ? '[]' : ''}`, isInput, true), }, { key: `${keyPrefix}status`, @@ -43,7 +41,7 @@ module.exports = { ] }, mapping: (bundle, prefix = '') => { - let keyPrefix = prefix && `${prefix}.` + const {keyPrefix} = utils.buildKeyAndLabel(prefix) return { 'id': bundle.inputData?.[`${keyPrefix}id`], 'category': utils.removeIfEmpty(Category.mapping(bundle, `${keyPrefix}category`)), diff --git a/samples/client/petstore/zapier/models/Tag.js b/samples/client/petstore/zapier/models/Tag.js index ce2097ffed05..1c543e14767f 100644 --- a/samples/client/petstore/zapier/models/Tag.js +++ b/samples/client/petstore/zapier/models/Tag.js @@ -1,10 +1,8 @@ -const _ = require('lodash') const utils = require('../utils/utils'); module.exports = { - fields: (prefix = '', isInput = true) => { - let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` - let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + fields: (prefix = '', isInput = true, isArrayChild = false) => { + const {keyPrefix, labelPrefix} = utils.buildKeyAndLabel(prefix, isInput, isArrayChild) return [ { key: `${keyPrefix}id`, @@ -19,7 +17,7 @@ module.exports = { ] }, mapping: (bundle, prefix = '') => { - let keyPrefix = prefix && `${prefix}.` + const {keyPrefix} = utils.buildKeyAndLabel(prefix) return { 'id': bundle.inputData?.[`${keyPrefix}id`], 'name': bundle.inputData?.[`${keyPrefix}name`], diff --git a/samples/client/petstore/zapier/models/User.js b/samples/client/petstore/zapier/models/User.js index fc94a6fd567c..7ea88814d6eb 100644 --- a/samples/client/petstore/zapier/models/User.js +++ b/samples/client/petstore/zapier/models/User.js @@ -1,10 +1,8 @@ -const _ = require('lodash') const utils = require('../utils/utils'); module.exports = { - fields: (prefix = '', isInput = true) => { - let keyPrefix = prefix && `${prefix}${isInput ? '.' : '__'}` - let labelPrefix = keyPrefix && keyPrefix.replaceAll('__', '.') + fields: (prefix = '', isInput = true, isArrayChild = false) => { + const {keyPrefix, labelPrefix} = utils.buildKeyAndLabel(prefix, isInput, isArrayChild) return [ { key: `${keyPrefix}id`, @@ -49,7 +47,7 @@ module.exports = { ] }, mapping: (bundle, prefix = '') => { - let keyPrefix = prefix && `${prefix}.` + const {keyPrefix} = utils.buildKeyAndLabel(prefix) return { 'id': bundle.inputData?.[`${keyPrefix}id`], 'username': bundle.inputData?.[`${keyPrefix}username`], diff --git a/samples/client/petstore/zapier/utils/utils.js b/samples/client/petstore/zapier/utils/utils.js index cfc027c9ad24..6d49446a60d8 100644 --- a/samples/client/petstore/zapier/utils/utils.js +++ b/samples/client/petstore/zapier/utils/utils.js @@ -3,6 +3,14 @@ const _ = require('lodash') const replacePathParameters = (url) => url.replace(/{([^{}]+)}/g, (keyExpr, key) => `{{bundle.inputData.${key}}}`) const removeKeyPrefixes = (objectsArray) => objectsArray == undefined || typeof objectsArray[0] != 'object' ? objectsArray : objectsArray.map((obj) => Object.keys(obj).reduce((res, key) => (res[(key.split('.')).slice(-1)] = obj[key], res), {})) const removeIfEmpty = (obj) => _.isEmpty(JSON.parse(JSON.stringify(obj))) ? undefined : obj +const buildKeyAndLabel = (prefix, isInput = true, isArrayChild = false) => { + const keyPrefix = !_.isEmpty(prefix) && (!isArrayChild || isInput) ? `${prefix}${isInput ? '.' : '__'}` : prefix + const labelPrefix = !_.isEmpty(keyPrefix) ? keyPrefix.replaceAll('__', '.') : '' + return { + keyPrefix: keyPrefix, + labelPrefix:labelPrefix, + } +} const hasASearchField = action => action.operation.inputFields.length > 0 const isSearchAction = (key) => { // TODO: custom logic @@ -17,6 +25,7 @@ module.exports = { replacePathParameters: replacePathParameters, removeKeyPrefixes: removeKeyPrefixes, removeIfEmpty: removeIfEmpty, + buildKeyAndLabel: buildKeyAndLabel, hasASearchField: hasASearchField, isSearchAction: isSearchAction, searchMiddleware: searchMiddleware, From 46932468a53db7604e54b781e8c3572351af284b Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Thu, 6 Jul 2023 15:33:21 +0200 Subject: [PATCH 19/20] improved zapier search actions --- .../src/main/resources/zapier/actions.mustache | 4 ++-- .../src/main/resources/zapier/utils.mustache | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/zapier/actions.mustache b/modules/openapi-generator/src/main/resources/zapier/actions.mustache index 6dbe5f0e2f1e..d398927b6d82 100644 --- a/modules/openapi-generator/src/main/resources/zapier/actions.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/actions.mustache @@ -3,7 +3,7 @@ const {{classname}} = require('../{{apiPackage}}/{{classname}}'); {{/apis}} {{/apiInfo}} -const { searchMiddleware, hasASearchField, isSearchAction } = require('../utils/utils'); +const { searchMiddleware, hasSearchRequisites, isSearchAction } = require('../utils/utils'); const actions = { {{#apiInfo}} @@ -18,6 +18,6 @@ const actions = { } module.exports = { - searchActions: () => Object.entries(actions).reduce((actions, [key, value]) => isSearchAction(key) && hasASearchField(value) ? {...actions, [key]: searchMiddleware(value)} : actions, {}), + searchActions: () => Object.entries(actions).reduce((actions, [key, value]) => isSearchAction(key) && hasSearchRequisites(value) ? {...actions, [key]: searchMiddleware(value)} : actions, {}), createActions: () => Object.entries(actions).reduce((actions, [key, value]) => !isSearchAction(key) ? {...actions, [key]: value} : actions, {}), } \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/zapier/utils.mustache b/modules/openapi-generator/src/main/resources/zapier/utils.mustache index 6d49446a60d8..89690f26657c 100644 --- a/modules/openapi-generator/src/main/resources/zapier/utils.mustache +++ b/modules/openapi-generator/src/main/resources/zapier/utils.mustache @@ -11,11 +11,13 @@ const buildKeyAndLabel = (prefix, isInput = true, isArrayChild = false) => { labelPrefix:labelPrefix, } } -const hasASearchField = action => action.operation.inputFields.length > 0 const isSearchAction = (key) => { // TODO: custom logic return false } +const hasASearchField = action => action.operation.inputFields.length > 0 +const returnsObjectsArray = action => !!action.operation.outputFields.find(field => 'children' in field) +const hasSearchRequisites = action => hasASearchField(action) && returnsObjectsArray(action) const searchMiddleware = (action) => { // TODO: custom logic return action @@ -26,7 +28,7 @@ module.exports = { removeKeyPrefixes: removeKeyPrefixes, removeIfEmpty: removeIfEmpty, buildKeyAndLabel: buildKeyAndLabel, - hasASearchField: hasASearchField, + hasSearchRequisites: hasSearchRequisites, isSearchAction: isSearchAction, searchMiddleware: searchMiddleware, } \ No newline at end of file From 087eb8e0fda88788c7f2cc2e59fffe6eee64a7f0 Mon Sep 17 00:00:00 2001 From: Emanuele Saccomandi Date: Thu, 6 Jul 2023 16:55:17 +0200 Subject: [PATCH 20/20] updated samples --- samples/client/petstore/zapier/operations/actions.js | 4 ++-- samples/client/petstore/zapier/utils/utils.js | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/samples/client/petstore/zapier/operations/actions.js b/samples/client/petstore/zapier/operations/actions.js index e6d77cdb53e3..d9a6a9afbbab 100644 --- a/samples/client/petstore/zapier/operations/actions.js +++ b/samples/client/petstore/zapier/operations/actions.js @@ -1,7 +1,7 @@ const PetApi = require('../apis/PetApi'); const StoreApi = require('../apis/StoreApi'); const UserApi = require('../apis/UserApi'); -const { searchMiddleware, hasASearchField, isSearchAction } = require('../utils/utils'); +const { searchMiddleware, hasSearchRequisites, isSearchAction } = require('../utils/utils'); const actions = { [PetApi.addPet.key]: PetApi.addPet, @@ -27,6 +27,6 @@ const actions = { } module.exports = { - searchActions: () => Object.entries(actions).reduce((actions, [key, value]) => isSearchAction(key) && hasASearchField(value) ? {...actions, [key]: searchMiddleware(value)} : actions, {}), + searchActions: () => Object.entries(actions).reduce((actions, [key, value]) => isSearchAction(key) && hasSearchRequisites(value) ? {...actions, [key]: searchMiddleware(value)} : actions, {}), createActions: () => Object.entries(actions).reduce((actions, [key, value]) => !isSearchAction(key) ? {...actions, [key]: value} : actions, {}), } \ No newline at end of file diff --git a/samples/client/petstore/zapier/utils/utils.js b/samples/client/petstore/zapier/utils/utils.js index 6d49446a60d8..89690f26657c 100644 --- a/samples/client/petstore/zapier/utils/utils.js +++ b/samples/client/petstore/zapier/utils/utils.js @@ -11,11 +11,13 @@ const buildKeyAndLabel = (prefix, isInput = true, isArrayChild = false) => { labelPrefix:labelPrefix, } } -const hasASearchField = action => action.operation.inputFields.length > 0 const isSearchAction = (key) => { // TODO: custom logic return false } +const hasASearchField = action => action.operation.inputFields.length > 0 +const returnsObjectsArray = action => !!action.operation.outputFields.find(field => 'children' in field) +const hasSearchRequisites = action => hasASearchField(action) && returnsObjectsArray(action) const searchMiddleware = (action) => { // TODO: custom logic return action @@ -26,7 +28,7 @@ module.exports = { removeKeyPrefixes: removeKeyPrefixes, removeIfEmpty: removeIfEmpty, buildKeyAndLabel: buildKeyAndLabel, - hasASearchField: hasASearchField, + hasSearchRequisites: hasSearchRequisites, isSearchAction: isSearchAction, searchMiddleware: searchMiddleware, } \ No newline at end of file