diff --git a/bin/configs/zapier-petstore-new.yaml b/bin/configs/zapier-petstore-new.yaml
new file mode 100644
index 00000000000..b57c9594850
--- /dev/null
+++ b/bin/configs/zapier-petstore-new.yaml
@@ -0,0 +1,7 @@
+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:
+ npmVersion: 0.0.1
+ npmName: '@openapitools/zapier'
\ No newline at end of file
diff --git a/docs/generators.md b/docs/generators.md
index c1adb82b6d6..6b175338702 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -74,6 +74,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 00000000000..f054dcd0a6c
--- /dev/null
+++ b/docs/generators/zapier.md
@@ -0,0 +1,178 @@
+---
+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
+- object
+- 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
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 00000000000..52bb93222e2
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ZapierClientCodegen.java
@@ -0,0 +1,199 @@
+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.*;
+
+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 {
+ 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", ".js");
+ 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", "object")
+ );
+
+ 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");
+ }
+
+ @Override
+ protected void initializeSpecialCharacterMapping() {
+ super.initializeSpecialCharacterMapping();
+ specialCharReplacements.remove("_");
+ }
+
+ /**
+ * 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 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;
+ }
+
+ @Override
+ public String toApiTestFilename(String name) {
+ return toApiName(name);
+ }
+
+ @Override
+ public GeneratorLanguage generatorLanguage() { return null; }
+
+ @Override
+ public String escapeUnsafeCharacters(String input) {
+ return input;
+ }
+
+ @Override
+ public String escapeQuotationMark(String input) {
+ 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();
+ r.examples = toExamples(example.get("examples"));
+ } catch (Exception e) {
+ LOGGER.error(e.toString());
+ }
+ return r;
+ }
+
+ @Override
+ protected List