diff --git a/bin/configs/postman-collection.yaml b/bin/configs/postman-collection.yaml
new file mode 100644
index 00000000000..badae7aad49
--- /dev/null
+++ b/bin/configs/postman-collection.yaml
@@ -0,0 +1,4 @@
+generatorName: postman-collection
+outputDir: samples/schema/postman-collection
+inputSpec: modules/openapi-generator/src/test/resources/3_0/postman-collection/SampleProject.yaml
+templateDir: modules/openapi-generator/src/main/resources/postman-collection
diff --git a/docs/generators.md b/docs/generators.md
index ad8ee6fa062..09ca42bdb3d 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -153,6 +153,7 @@ The following generators are available:
* [graphql-schema](generators/graphql-schema.md)
* [ktorm-schema (beta)](generators/ktorm-schema.md)
* [mysql-schema](generators/mysql-schema.md)
+* [postman-collection (beta)](generators/postman-collection.md)
* [protobuf-schema (beta)](generators/protobuf-schema.md)
* [wsdl-schema (beta)](generators/wsdl-schema.md)
diff --git a/docs/generators/postman-collection.md b/docs/generators/postman-collection.md
new file mode 100644
index 00000000000..a0a97b43f06
--- /dev/null
+++ b/docs/generators/postman-collection.md
@@ -0,0 +1,166 @@
+---
+title: Documentation for the postman-collection Generator
+---
+
+## METADATA
+
+| Property | Value | Notes |
+| -------- | ----- | ----- |
+| generator name | postman-collection | pass this to the generate command after -g |
+| generator stability | BETA | |
+| generator type | SCHEMA | |
+| generator default templating engine | mustache | |
+| helpTxt | Generates a Postman collection (format v2.1.0) JSON file | |
+
+## 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 |
+| ------ | ----------- | ------ | ------- |
+|folderStrategy|whether to create folders according to the spec’s paths or tags| |null|
+|pathParamsAsVariables|whether to create Postman variables for path parameters| |false|
+|postmanGuid|whether to convert placeholders (i.e. {{UNIQUE_REFERENCE}}) into Postman formula {{$guid}}| |null|
+|postmanGuidPlaceholderName|name of the placeholder (i.e. {{UNIQUE_REFERENCE}}) to replace with Postman formula {{$guid}}| |null|
+|postmanIsoTimestamp|whether to convert placeholders (i.e. {{ISO_TIMESTAMP}}) into Postman formula {{$isoTimestamp}}| |null|
+|postmanIsoTimestampPlaceholderName|name of the placeholder (i.e. {{ISO_TIMESTAMP}}) to replace with Postman formula {{$isoTimestamp}}| |null|
+|postmanVariables|whether to convert placeholders (i.e. {{VAR_1}}) into Postman variables| |null|
+|requestParameterGeneration|whether to generate the request parameters based on the schema or the examples| |null|
+
+## IMPORT MAPPING
+
+| Type/Alias | Imports |
+| ---------- | ------- |
+
+
+## INSTANTIATION TYPES
+
+| Type/Alias | Instantiated By |
+| ---------- | --------------- |
+
+
+## LANGUAGE PRIMITIVES
+
+
+
+## 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
+
+### Wire Format Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|JSON|✓|OAS2,OAS3
+|XML|✓|OAS2,OAS3
+|PROTOBUF|✗|ToolingExtension
+|Custom|✗|OAS2,OAS3
diff --git a/docs/generators/postman.md b/docs/generators/postman.md
new file mode 100644
index 00000000000..2502469bcd0
--- /dev/null
+++ b/docs/generators/postman.md
@@ -0,0 +1,166 @@
+---
+title: Documentation for the postman Generator
+---
+
+## METADATA
+
+| Property | Value | Notes |
+| -------- | ----- | ----- |
+| generator name | postman | pass this to the generate command after -g |
+| generator stability | BETA | |
+| generator type | DOCUMENTATION | |
+| generator default templating engine | mustache | |
+| helpTxt | Generates a postman JSON file | |
+
+## 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 |
+| ------ | ----------- | ------ | ------- |
+|folderStrategy|whether to create folders according to the spec’s paths or tags| |null|
+|pathParamsAsVariables|whether to create Postman variables for path parameters| |false|
+|postmanGuid|whether to convert placeholders (i.e. {{UNIQUE_REFERENCE}}) into Postman formula {{$guid}}| |null|
+|postmanGuidPlaceholderName|name of the placeholder (i.e. {{UNIQUE_REFERENCE}}) to replace with Postman formula {{$guid}}| |null|
+|postmanIsoTimestamp|whether to convert placeholders (i.e. {{ISO_TIMESTAMP}}) into Postman formula {{$isoTimestamp}}| |null|
+|postmanIsoTimestampPlaceholderName|name of the placeholder (i.e. {{ISO_TIMESTAMP}}) to replace with Postman formula {{$isoTimestamp}}| |null|
+|postmanVariables|whether to convert placeholders (i.e. {{VAR_1}}) into Postman variables| |null|
+|requestParameterGeneration|whether to generate the request parameters based on the schema or the examples| |null|
+
+## IMPORT MAPPING
+
+| Type/Alias | Imports |
+| ---------- | ------- |
+
+
+## INSTANTIATION TYPES
+
+| Type/Alias | Instantiated By |
+| ---------- | --------------- |
+
+
+## LANGUAGE PRIMITIVES
+
+
+
+## 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
+
+### 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/PostmanCollectionCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PostmanCollectionCodegen.java
new file mode 100644
index 00000000000..06e633a4acc
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PostmanCollectionCodegen.java
@@ -0,0 +1,844 @@
+package org.openapitools.codegen.languages;
+
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import io.swagger.v3.core.util.Json;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.examples.Example;
+import io.swagger.v3.oas.models.servers.ServerVariable;
+import org.openapitools.codegen.*;
+import org.openapitools.codegen.meta.GeneratorMetadata;
+import org.openapitools.codegen.meta.Stability;
+import org.openapitools.codegen.model.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * OpenAPI generator for Postman Collection format v2.1
+ */
+public class PostmanCollectionCodegen extends DefaultCodegen implements CodegenConfig {
+
+ private final Logger LOGGER = LoggerFactory.getLogger(PostmanCollectionCodegen.class);
+
+ protected String apiVersion = "1.0.0";
+
+ // Select whether to create folders according to the spec’s paths or tags. Values: Paths | Tags
+ public static final String FOLDER_STRATEGY = "folderStrategy";
+ public static final String FOLDER_STRATEGY_DEFAULT_VALUE = "Tags";
+ // Select whether to create Postman variables for path templates
+ public static final String PATH_PARAMS_AS_VARIABLES = "pathParamsAsVariables";
+ public static final Boolean PATH_PARAMS_AS_VARIABLES_DEFAULT_VALUE = true;
+
+ public static final String POSTMAN_FILE_DEFAULT_VALUE = "postman.json";
+
+ // create Postman variables from placeholders ie {{VAR_1}}
+ public static final String POSTMAN_VARIABLES = "postmanVariables";
+ protected Boolean postmanVariables = true;
+ // replace placeholder `UNIQUE_REFERENCE` with Postman {{$guid}}
+ public static final String POSTMAN_GUID = "postmanGuid";
+ protected Boolean postmanGuid = true;
+ // default guid placeholder name
+ public static final String POSTMAN_GUID_PLACEHOLDER_NAME = "postmanGuidPlaceholderName";
+ protected static final String POSTMAN_GUID_PLACEHOLDER_NAME_DEFAULT_VALUE = "UNIQUE_REFERENCE";
+ protected static String postmanGuidPlaceholderName = POSTMAN_GUID_PLACEHOLDER_NAME_DEFAULT_VALUE;
+ // replace placeholder `ISO_TIMESTAMP` with Postman {{isoTimestamp}}
+ protected Boolean postmanIsoTimestamp = true;
+ public static final String POSTMAN_ISO_TIMESTAMP = "postmanIsoTimestamp";
+ public static final String POSTMAN_ISO_TIMESTAMP_PLACEHOLDER_NAME = "postmanIsoTimestampPlaceholderName";
+ public static final String POSTMAN_ISO_TIMESTAMP_PLACEHOLDER_NAME_DEFAULT_VALUE = "ISO_TIMESTAMP";
+ protected static String postmanIsoTimestampPlaceholderName = POSTMAN_ISO_TIMESTAMP_PLACEHOLDER_NAME_DEFAULT_VALUE;
+
+ public static final String REQUEST_PARAMETER_GENERATION = "requestParameterGeneration";
+ public static final String REQUEST_PARAMETER_GENERATION_DEFAULT_VALUE = "Example";
+
+ public String folderStrategy = FOLDER_STRATEGY_DEFAULT_VALUE; // values: Paths | Tags
+ protected Boolean pathParamsAsVariables = PATH_PARAMS_AS_VARIABLES_DEFAULT_VALUE; // values: true | false
+
+ // Output file
+ public String postmanFile = POSTMAN_FILE_DEFAULT_VALUE;
+
+ // Select whether to generate requests/responses from Example or Schema
+ protected String requestParameterGeneration = REQUEST_PARAMETER_GENERATION_DEFAULT_VALUE; // values: Example, Schema
+
+ public Set variables = new HashSet<>();
+
+ public static final String JSON_ESCAPE_DOUBLE_QUOTE = "\\\"";
+ public static final String JSON_ESCAPE_NEW_LINE = "\\n";
+
+
+ // operations grouped by tag
+ protected Map> codegenOperationsByTag = new HashMap<>();
+ // list of operations
+ protected List codegenOperationsList = new ArrayList<>();
+
+ /**
+ * Configures the type of generator.
+ *
+ * @return the CodegenType for this generator
+ * @see org.openapitools.codegen.CodegenType
+ */
+ public CodegenType getTag() {
+ return CodegenType.SCHEMA;
+ }
+
+ @Override
+ public GeneratorLanguage generatorLanguage() {
+ return null;
+ }
+
+
+ /**
+ * Configures a friendly name for the generator. This will be used by the generator
+ * to select the library with the -g flag.
+ *
+ * @return the friendly name for the generator
+ */
+ public String getName() {
+ return "postman-collection";
+ }
+
+ public PostmanCollectionCodegen() {
+ super();
+
+ generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
+ .stability(Stability.BETA)
+ .build();
+
+ embeddedTemplateDir = templateDir = "postman-collection";
+ supportingFiles.add(
+ new SupportingFile("postman.mustache", "", postmanFile)
+ );
+
+ cliOptions.clear();
+ cliOptions.add(CliOption.newString(FOLDER_STRATEGY, "whether to create folders according to the spec’s paths or tags"));
+ cliOptions.add(CliOption.newBoolean(PATH_PARAMS_AS_VARIABLES, "whether to create Postman variables for path parameters"));
+ cliOptions.add(CliOption.newString(POSTMAN_VARIABLES, "whether to convert placeholders (i.e. {{VAR_1}}) into Postman variables"));
+ cliOptions.add(CliOption.newString(POSTMAN_GUID, "whether to convert placeholders (i.e. {{UNIQUE_REFERENCE}}) into Postman formula {{$guid}}"));
+ cliOptions.add(CliOption.newString(POSTMAN_GUID_PLACEHOLDER_NAME, "name of the placeholder (i.e. {{UNIQUE_REFERENCE}}) to replace with Postman formula {{$guid}}"));
+ cliOptions.add(CliOption.newString(POSTMAN_ISO_TIMESTAMP, "whether to convert placeholders (i.e. {{ISO_TIMESTAMP}}) into Postman formula {{$isoTimestamp}}"));
+ cliOptions.add(CliOption.newString(POSTMAN_ISO_TIMESTAMP_PLACEHOLDER_NAME, "name of the placeholder (i.e. {{ISO_TIMESTAMP}}) to replace with Postman formula {{$isoTimestamp}}"));
+ cliOptions.add(CliOption.newString(REQUEST_PARAMETER_GENERATION, "whether to generate the request parameters based on the schema or the examples"));
+
+ }
+
+ @Override
+ public void postProcessParameter(CodegenParameter parameter) {
+ if(pathParamsAsVariables && parameter.isPathParam) {
+ variables.add(new PostmanVariable()
+ .addName(parameter.paramName)
+ .addType(mapToPostmanType(parameter.dataType))
+ .addExample(parameter.example));
+ }
+ }
+
+ @Override
+ public void preprocessOpenAPI(OpenAPI openAPI) {
+ super.preprocessOpenAPI(openAPI);
+ this.additionalProperties().put("formattedDescription", formatDescription(openAPI.getInfo().getDescription()));
+ }
+
+ @Override
+ public List fromServerVariables(Map variables) {
+
+ if(variables != null){
+ variables.entrySet().stream().forEach(serverVariableEntry -> this.variables.add(new PostmanVariable()
+ .addName(serverVariableEntry.getKey())
+ .addType("string")
+ .addExample(serverVariableEntry.getValue().getDefault())));
+ }
+
+ return super.fromServerVariables(variables);
+ }
+
+ @Override
+ public void processOpts() {
+ super.processOpts();
+
+ if(additionalProperties().containsKey(FOLDER_STRATEGY)) {
+ folderStrategy = additionalProperties().get(FOLDER_STRATEGY).toString();
+ }
+
+ if (additionalProperties.containsKey(PATH_PARAMS_AS_VARIABLES)) {
+ pathParamsAsVariables = Boolean.parseBoolean(additionalProperties.get(PATH_PARAMS_AS_VARIABLES).toString());
+ }
+
+ if(additionalProperties().containsKey(REQUEST_PARAMETER_GENERATION)) {
+ requestParameterGeneration = additionalProperties().get(REQUEST_PARAMETER_GENERATION).toString();
+ }
+
+ if(additionalProperties().containsKey(POSTMAN_VARIABLES)) {
+ postmanVariables = Boolean.parseBoolean(additionalProperties.get(POSTMAN_VARIABLES).toString());
+ }
+
+ if(additionalProperties().containsKey(POSTMAN_GUID)) {
+ postmanGuid = Boolean.parseBoolean(additionalProperties.get(POSTMAN_GUID).toString());
+ }
+
+ if(additionalProperties().containsKey(POSTMAN_GUID_PLACEHOLDER_NAME)) {
+ postmanGuidPlaceholderName = additionalProperties.get(POSTMAN_GUID_PLACEHOLDER_NAME).toString();
+ }
+
+ if(additionalProperties().containsKey(POSTMAN_ISO_TIMESTAMP)) {
+ postmanIsoTimestamp = Boolean.parseBoolean(additionalProperties.get(POSTMAN_ISO_TIMESTAMP).toString());
+ }
+
+ if(additionalProperties().containsKey(POSTMAN_ISO_TIMESTAMP_PLACEHOLDER_NAME)) {
+ postmanIsoTimestampPlaceholderName = additionalProperties.get(POSTMAN_ISO_TIMESTAMP_PLACEHOLDER_NAME).toString();
+ }
+
+ super.vendorExtensions().put("variables", variables);
+
+ if(folderStrategy.equalsIgnoreCase("tags")) {
+ this.additionalProperties().put("codegenOperationsByTag", codegenOperationsByTag);
+ } else {
+ this.additionalProperties().put("codegenOperationsList", codegenOperationsList);
+ }
+
+ }
+
+ /**
+ * Process and modify operations before generating code
+ */
+ @Override
+ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List allModels) {
+ OperationsMap results = super.postProcessOperationsWithModels(objs, allModels);
+
+ OperationMap ops = results.getOperations();
+ List opList = ops.getOperation();
+
+ for(CodegenOperation codegenOperation : opList) {
+
+ if(pathParamsAsVariables) {
+ codegenOperation.path = doubleCurlyBraces(codegenOperation.path);
+ }
+
+ codegenOperation.summary = getSummary(codegenOperation);
+
+ // request headers
+ if(codegenOperation.produces != null && codegenOperation.produces.get(0) != null) {
+ // produces mediaType as `Accept` header (use first mediaType only)
+ String mediaType = codegenOperation.produces.get(0).get("mediaType");
+ CodegenParameter acceptHeader = new CodegenParameter();
+ acceptHeader.paramName = "Accept";
+ CodegenProperty schema = new CodegenProperty();
+ schema.defaultValue = mediaType;
+ acceptHeader.setSchema(schema);
+ codegenOperation.headerParams.add(0, acceptHeader);
+ }
+
+ if(codegenOperation.consumes != null && codegenOperation.consumes.get(0) != null) {
+ // consumes mediaType as `Content-Type` header (use first mediaType only)
+ String mediaType = codegenOperation.consumes.get(0).get("mediaType");
+ CodegenParameter contentTypeHeader = new CodegenParameter();
+ contentTypeHeader.paramName = "Content-Type";
+ CodegenProperty schema = new CodegenProperty();
+ schema.defaultValue = mediaType;
+ contentTypeHeader.setSchema(schema);
+ codegenOperation.headerParams.add(0, contentTypeHeader);
+ }
+
+ // build pathSegments
+ String[] pathSegments = codegenOperation.path.substring(1).split("/");
+ codegenOperation.vendorExtensions.put("pathSegments", pathSegments);
+ codegenOperation.responses.stream().forEach(r -> r.vendorExtensions.put("pathSegments", pathSegments));
+
+ List postmanRequests = getPostmanRequests(codegenOperation);
+ if(postmanRequests != null) {
+ if(postmanVariables) {
+ postmanRequests = createPostmanVariables(postmanRequests);
+ }
+ if(postmanGuid) {
+ postmanRequests = setPostmanGuid(postmanRequests);
+ }
+ if(postmanIsoTimestamp) {
+ postmanRequests = setPostmanIsoTimestamp(postmanRequests);
+ }
+ codegenOperation.vendorExtensions.put("postmanRequests", postmanRequests);
+ }
+
+ // set all available responses
+ for(CodegenResponse codegenResponse : codegenOperation.responses) {
+
+ codegenResponse.vendorExtensions.put("status", getStatus(codegenResponse));
+
+// TODO: set response for each request
+// if(postmanRequests != null) {
+// // re-use request body for each response
+// codegenResponse.vendorExtensions.put("requestBody", postmanRequests);
+// }
+// String responseBody = getResponseBody(codegenResponse);
+// if(responseBody != null) {
+// codegenResponse.vendorExtensions.put("responseBody", responseBody);
+// codegenResponse.vendorExtensions.put("hasResponseBody", true);
+// } else {
+// codegenResponse.vendorExtensions.put("hasResponseBody", false);
+// }
+
+ }
+
+ if(folderStrategy.equalsIgnoreCase("tags")) {
+ addToMap(codegenOperation);
+ } else {
+ addToList(codegenOperation);
+ }
+
+ }
+
+ return results;
+ }
+
+
+ /**
+ * Add the CodegenOperation to the map that is passed to the Mustache templates
+ * The map groups the CodegenOperations by tag as defined in the OpenAPI spec
+ * @param codegenOperation Codegen operation instance
+ */
+ void addToMap(CodegenOperation codegenOperation){
+
+ String key = null;
+ if(codegenOperation.tags == null || codegenOperation.tags.isEmpty()) {
+ key = "default";
+ } else {
+ key = codegenOperation.tags.get(0).getName();
+ }
+
+ List list = codegenOperationsByTag.get(key);
+
+ if(list == null) {
+ list = new ArrayList<>();
+ }
+ list.add(codegenOperation);
+
+ codegenOperationsByTag.put(key, list);
+
+ }
+
+ void addToList(CodegenOperation codegenOperation) {
+ codegenOperationsList.add(codegenOperation);
+ }
+
+ String getResponseBody(CodegenResponse codegenResponse) {
+ String responseBody = "";
+
+ if(codegenResponse.getContent() != null && codegenResponse.getContent().get("application/json") != null &&
+ codegenResponse.getContent().get("application/json").getExamples() != null) {
+ // find in components/examples
+ String exampleRef = codegenResponse.getContent().get("application/json").getExamples()
+ .values().iterator().next().get$ref();
+ if(exampleRef != null) {
+ Example example = this.openAPI.getComponents().getExamples().get(extractExampleByName(exampleRef));
+ responseBody = getJsonFromExample(example);
+ }
+ } else if(codegenResponse.getContent() != null) {
+ // find in context examples
+ Map maxExamples = codegenResponse.getContent().get("application/json").getExamples();
+ if(maxExamples != null && maxExamples.values().iterator().hasNext()) {
+ responseBody = getJsonFromExample(maxExamples.values().iterator().next());
+ }
+ }
+
+ return responseBody;
+ }
+
+ // from OpenAPI operation to n Postman requests
+ List getPostmanRequests(CodegenOperation codegenOperation) {
+ List items = new ArrayList<>();
+
+ if(codegenOperation.getHasBodyParam()) {
+ // operation with bodyParam
+ if (requestParameterGeneration.equalsIgnoreCase("Schema")) {
+ // get from schema
+ items.add(new PostmanRequestItem(codegenOperation.summary, getJsonFromSchema(codegenOperation.bodyParam)));
+ } else {
+ // get from examples
+ if (codegenOperation.bodyParam.example != null) {
+ // find in bodyParam example
+ items.add(new PostmanRequestItem(codegenOperation.summary, formatJson(codegenOperation.bodyParam.example)));
+ } else if (codegenOperation.bodyParam.getContent().get("application/json") != null &&
+ codegenOperation.bodyParam.getContent().get("application/json").getExamples() != null) {
+ // find in components/examples
+ for (Map.Entry entry : codegenOperation.bodyParam.getContent().get("application/json").getExamples().entrySet()) {
+ String exampleRef = entry.getValue().get$ref();
+ Example example = this.openAPI.getComponents().getExamples().get(extractExampleByName(exampleRef));
+ String exampleAsString = getJsonFromExample(example);
+
+ items.add(new PostmanRequestItem(example.getSummary(), exampleAsString));
+ }
+ } else if (codegenOperation.bodyParam.getSchema() != null) {
+ // find in schema example
+ String exampleAsString = formatJson(codegenOperation.bodyParam.getSchema().getExample());
+ items.add(new PostmanRequestItem(codegenOperation.summary, exampleAsString));
+ } else {
+ // example not found
+ // get from schema
+ items.add(new PostmanRequestItem(codegenOperation.summary, getJsonFromSchema(codegenOperation.bodyParam)));
+
+ }
+ }
+ } else {
+ // operation without bodyParam
+ items.add(new PostmanRequestItem(codegenOperation.summary, ""));
+ }
+
+ return items;
+ }
+
+ // from placeholders (ie {{VAR_1}}) create Postman variables
+ public List createPostmanVariables(List postmanRequests) {
+
+ for(PostmanRequestItem requestItem : postmanRequests) {
+ for(String var: extractPlaceholders(requestItem.getBody())) {
+ variables.add(new PostmanVariable()
+ .addName(var)
+ .addType("string")
+ .addExample(""));
+ }
+ }
+
+ return postmanRequests;
+ }
+
+ // replace postmanGuid placeholder (ie {{UNIQUE_REFERENCE}}) with Postman formula {{$guid}}
+ List setPostmanGuid(List postmanRequests) {
+
+ for(PostmanRequestItem requestItem : postmanRequests) {
+ requestItem.setBody(requestItem.getBody().replace("{{" + postmanGuidPlaceholderName + "}}", "{{$guid}}"));
+ }
+
+ return postmanRequests;
+ }
+
+ // replace postman placeholder (ie {{ISO_TIMESTAMP}}) with Postman formula {{$isoTimestamp}}
+ List setPostmanIsoTimestamp(List postmanRequests) {
+
+ for(PostmanRequestItem requestItem : postmanRequests) {
+ requestItem.setBody(requestItem.getBody().replace("{{" + postmanIsoTimestampPlaceholderName + "}}", "{{$isoTimestamp}}"));
+ }
+
+ return postmanRequests;
+ }
+
+ /**
+ * Returns human-friendly help for the generator. Provide the consumer with help
+ * tips, parameters here
+ *
+ * @return A string value for the help message
+ */
+ public String getHelp() {
+ return "Generates a Postman collection (format v2.1.0) JSON file";
+ }
+
+ /**
+ * Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
+ * those terms here. This logic is only called if a variable matches the reserved words
+ *
+ * @return the escaped term
+ */
+ @Override
+ public String escapeReservedWord(String name) {
+ return "_" + name; // add an underscore to the name
+ }
+
+ /**
+ * override with any special text escaping logic to handle unsafe
+ * characters so as to avoid code injection
+ *
+ * @param input String to be cleaned up
+ * @return string with unsafe characters removed or escaped
+ */
+ @Override
+ public String escapeUnsafeCharacters(String input) {
+ //TODO: check that this logic is safe to escape unsafe characters to avoid code injection
+ return input;
+ }
+
+ /**
+ * Escape single and/or double quote to avoid code injection
+ *
+ * @param input String to be cleaned up
+ * @return string with quotation mark removed or escaped
+ */
+ public String escapeQuotationMark(String input) {
+ //TODO: check that this logic is safe to escape quotation mark to avoid code injection
+ return input.replace("\"", "\\\"");
+ }
+
+ public String doubleCurlyBraces(String str) {
+
+ // remove doublebraces first
+ String s = str.replace("{{", "{").replace("}}", "}");
+ // change all singlebraces to doublebraces
+ s = s.replace("{", "{{").replace("}", "}}");
+
+ return s;
+
+ }
+
+ public String extractExampleByName(String ref) {
+ return ref.substring(ref.lastIndexOf("/") + 1);
+ }
+
+ public String mapToPostmanType(String openApiDataType) {
+ String ret = "any"; // default value
+
+ if(openApiDataType.equalsIgnoreCase("string")) {
+ ret = "string";
+ } else if(openApiDataType.equalsIgnoreCase("number") ||
+ openApiDataType.equalsIgnoreCase("integer")) {
+ ret = "number";
+ } else if(openApiDataType.equalsIgnoreCase("boolean")) {
+ ret = "boolean";
+ }
+
+ return ret;
+ }
+
+ /**
+ * get HTTP Status Code as text
+ * @param codegenResponse
+ * @return
+ */
+ String getStatus(CodegenResponse codegenResponse) {
+ String ret = "";
+
+ if (codegenResponse.is2xx) {
+ if (codegenResponse.code.equalsIgnoreCase("200")) {
+ ret = "OK";
+ } else if (codegenResponse.code.equalsIgnoreCase("201")) {
+ ret = "Created";
+ } else {
+ ret = "Success";
+ }
+ } else if (codegenResponse.is3xx) {
+ ret = "Redirection";
+ }
+ if (codegenResponse.is4xx) {
+ if (codegenResponse.code.equalsIgnoreCase("400")) {
+ ret = "Bad Request";
+ } else if (codegenResponse.code.equalsIgnoreCase("401")) {
+ ret = "Unauthorized";
+ } else if (codegenResponse.code.equalsIgnoreCase("403")) {
+ ret = "Forbidden";
+ } else if (codegenResponse.code.equalsIgnoreCase("404")) {
+ ret = "Not Found";
+ } else if (codegenResponse.code.equalsIgnoreCase("409")) {
+ ret = "Conflict";
+ } else {
+ ret = "Client Error";
+ }
+ }
+ if (codegenResponse.is5xx) {
+ if (codegenResponse.code.equalsIgnoreCase("500")) {
+ ret = "Internal Server Error";
+ } else if (codegenResponse.code.equalsIgnoreCase("501")) {
+ ret = "Not Implemented";
+ } else {
+ ret = "Server Error";
+ }
+ }
+
+ return ret;
+ }
+
+ // make sure operation name is always set
+ String getSummary(CodegenOperation codegenOperation) {
+ String ret = null;
+
+ if(codegenOperation.summary != null) {
+ ret = codegenOperation.summary;
+ } else if (codegenOperation.operationId != null) {
+ ret = codegenOperation.operationId;
+ } else {
+ ret = codegenOperation.httpMethod;
+ }
+ return ret;
+ }
+
+ /**
+ * Format text to include in JSON file
+ * @param description Text to format
+ * @return Formatted text
+ */
+ public String formatDescription(String description) {
+
+ description = description.replace("\n", JSON_ESCAPE_NEW_LINE);
+ description = description.replace("\"", JSON_ESCAPE_DOUBLE_QUOTE);
+
+ return description;
+ }
+
+ /**
+ * Extract all placeholders (string delimited by curly braces ie {{PLACEHOLDER}}) from the input string
+ * @param input String containing the placeholders
+ * @return Set of placeholders found in the string
+ */
+ public Set extractPlaceholders(String input) {
+ Set variables = new HashSet<>();
+
+ Pattern pattern = Pattern.compile("\\{\\{([^}]*)\\}\\}");
+ Matcher matcher = pattern.matcher(input);
+
+ while(matcher.find()) {
+ if(postmanGuidPlaceholderName.equalsIgnoreCase(matcher.group(1))) {
+ // skip if it is postmanGuid placeholder
+ break;
+ }
+ if(postmanIsoTimestampPlaceholderName.equalsIgnoreCase(matcher.group(1))) {
+ // skip if it is postmanIsoTimestamp placeholder
+ break;
+ }
+ if(isPostmanDynamicVariable(matcher.group(1))) {
+ // skip if it is reserved words
+ break;
+ }
+
+ variables.add(matcher.group(1));
+ }
+
+ return variables;
+ }
+
+ public boolean isPostmanDynamicVariable(String value) {
+ boolean ret = false;
+
+ if(value.equals("$guid") || value.equals("$timestamp")) {
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ // Supporting helpers
+ public String getJsonFromSchema(CodegenParameter codegenParameter) {
+
+ String ret = "{" + JSON_ESCAPE_NEW_LINE + " ";
+
+ int numVars = codegenParameter.vars.size();
+ int counter = 1;
+
+ for (CodegenProperty codegenProperty : codegenParameter.vars) {
+ ret = ret + JSON_ESCAPE_DOUBLE_QUOTE + codegenProperty.baseName + JSON_ESCAPE_DOUBLE_QUOTE + ": " +
+ JSON_ESCAPE_DOUBLE_QUOTE + "<" + getPostmanType(codegenProperty) + ">" + JSON_ESCAPE_DOUBLE_QUOTE;
+
+ if(counter < numVars) {
+ // add comma unless last attribute
+ ret = ret + "," + JSON_ESCAPE_NEW_LINE + " ";
+ }
+ counter++;
+
+ }
+
+ ret = ret + JSON_ESCAPE_NEW_LINE + "}";
+
+ return ret;
+ }
+
+ public String getJsonFromExample(Example example) {
+ String ret = "";
+
+ if(example == null) {
+ return ret;
+ }
+
+ if(example.getValue() instanceof ObjectNode) {
+ ret = convertToJson((ObjectNode)example.getValue());
+ } else if(example.getValue() instanceof LinkedHashMap) {
+ ret = convertToJson((LinkedHashMap)example.getValue());
+ }
+
+ return ret;
+ }
+
+ // array of attributes from JSON payload (ignore commas within quotes)
+ public String[] getAttributes(String json) {
+ return json.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
+ }
+
+ public String convertToJson(ObjectNode objectNode) {
+ return formatJson(objectNode.toString());
+ }
+
+ // convert to JSON (string) escaping and formatting
+ public String convertToJson(LinkedHashMap linkedHashMap) {
+ String ret = "";
+
+ return traverseMap(linkedHashMap, ret);
+ }
+
+ public String formatJson(String json) {
+
+ ObjectMapper objectMapper = new ObjectMapper();
+
+ try {
+ // convert to JSON object and prettify
+ JsonNode actualObj = objectMapper.readTree(json);
+ json = Json.pretty(actualObj);
+ json = json.replace("\"", JSON_ESCAPE_DOUBLE_QUOTE);
+ json = json.replace("\n", JSON_ESCAPE_NEW_LINE);
+
+ } catch (JsonProcessingException e) {
+ LOGGER.warn("Error formatting JSON", e);
+ json = "";
+ }
+
+ return json;
+ }
+
+ // traverse recursively
+ private String traverseMap(LinkedHashMap linkedHashMap, String ret) {
+
+ ret = ret + "{" + JSON_ESCAPE_NEW_LINE + " ";
+
+ int numVars = linkedHashMap.entrySet().size();
+ int counter = 1;
+
+ for (Map.Entry mapElement : linkedHashMap.entrySet()) {
+ String key = mapElement.getKey();
+ Object value = mapElement.getValue();
+
+ if(value instanceof String) {
+ // unescape double quotes already escaped
+ value = ((String)value).replace("\\\"", "\"");
+
+ ret = ret + JSON_ESCAPE_DOUBLE_QUOTE + key + JSON_ESCAPE_DOUBLE_QUOTE + ": " +
+ JSON_ESCAPE_DOUBLE_QUOTE + value + JSON_ESCAPE_DOUBLE_QUOTE;
+ } else if (value instanceof Integer) {
+ ret = ret + JSON_ESCAPE_DOUBLE_QUOTE + key + JSON_ESCAPE_DOUBLE_QUOTE + ": " +
+ value;
+ } else if (value instanceof LinkedHashMap) {
+ String in = ret + JSON_ESCAPE_DOUBLE_QUOTE + key + JSON_ESCAPE_DOUBLE_QUOTE + ": ";
+ ret = traverseMap(((LinkedHashMap) value), in);
+ } else {
+ LOGGER.warn("Value type unrecognised: " + value.getClass());
+ }
+
+ if(counter < numVars) {
+ // add comma unless last attribute
+ ret = ret + "," + JSON_ESCAPE_NEW_LINE + " ";
+ }
+ counter++;
+ }
+
+ ret = ret + JSON_ESCAPE_NEW_LINE + "}";
+
+ return ret;
+ }
+
+ public String getPostmanType(CodegenProperty codegenProperty) {
+ if(codegenProperty.isNumeric) {
+ return "number";
+ } else if(codegenProperty.isDate) {
+ return "date";
+ } else {
+ return "string";
+ }
+ }
+
+ // Supporting models
+ public class PostmanRequestItem {
+
+ private String name;
+ private String body;
+
+ public PostmanRequestItem() {
+ }
+
+ public PostmanRequestItem(String name, String body) {
+ this.name = name;
+ this.body = body;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+ }
+
+ class PostmanVariable {
+
+ private String name;
+ private String type;
+ private String example;
+
+ public PostmanVariable addName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public PostmanVariable addType(String type) {
+ this.type = type;
+ return this;
+ }
+
+ public PostmanVariable addExample(String example) {
+ this.example = example;
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getExample() {
+ return example;
+ }
+
+ public void setExample(String example) {
+ this.example = example;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PostmanVariable that = (PostmanVariable) o;
+ return name.equals(that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name);
+ }
+
+ @Override
+ public String toString() {
+ return "PostmanVariable{" +
+ "name='" + name + '\'' +
+ ", type='" + type + '\'' +
+ ", example='" + example + '\'' +
+ '}';
+ }
+ }
+
+}
+
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 7abf01c75ab..cd6ec8d5672 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
@@ -98,6 +98,7 @@ org.openapitools.codegen.languages.PhpSlim4ServerCodegen
org.openapitools.codegen.languages.PhpSymfonyServerCodegen
org.openapitools.codegen.languages.PhpMezzioPathHandlerServerCodegen
org.openapitools.codegen.languages.PhpDataTransferClientCodegen
+org.openapitools.codegen.languages.PostmanCollectionCodegen
org.openapitools.codegen.languages.PowerShellClientCodegen
org.openapitools.codegen.languages.ProtobufSchemaCodegen
org.openapitools.codegen.languages.PythonClientCodegen
diff --git a/modules/openapi-generator/src/main/resources/postman-collection/item.mustache b/modules/openapi-generator/src/main/resources/postman-collection/item.mustache
new file mode 100644
index 00000000000..61ee0eb879c
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/postman-collection/item.mustache
@@ -0,0 +1,60 @@
+{
+ "name": "{{path}}{{#isDeprecated}} (DEPRECATED){{/isDeprecated}}",
+ "description": "{{{notes}}}",
+ "item": [
+ {{#vendorExtensions.postmanRequests}}
+ {
+ "name": "{{name}}",
+ "request": {
+ "method": "{{httpMethod}}",
+ "header": [
+ {{#headerParams}}
+ {
+ "key": "{{paramName}}",
+ "value": "{{schema.defaultValue}}"
+ }{{^-last}},{{/-last}}
+ {{/headerParams}}
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{{{body}}}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{=<% %>=}}{{baseUrl}}<%={{ }}=%>{{path}}",
+ "host": [
+ "{{=<% %>=}}{{baseUrl}}<%={{ }}=%>"
+ ],
+ "path": [
+ {{#vendorExtensions.pathSegments}}
+ "{{.}}"{{^-last}},{{/-last}}
+ {{/vendorExtensions.pathSegments}}
+ ],
+ "variable": [
+ {{#pathParams}}
+ {
+ "key": "{{paramName}}",
+ "value": "",
+ "description": "{{description}}"
+ }{{^-last}},{{/-last}}
+ {{/pathParams}}
+ ],
+ "query": [
+ {{#queryParams}}
+ {
+ "key": "{{paramName}}",
+ "value": "{{example}}"
+ }{{^-last}},{{/-last}}
+ {{/queryParams}}
+ ]
+ },
+ "description": "{{{notes}}}"
+ }
+ }{{^-last}},{{/-last}}
+ {{/vendorExtensions.postmanRequests}}
+ ]
+ }
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/postman-collection/postman.mustache b/modules/openapi-generator/src/main/resources/postman-collection/postman.mustache
new file mode 100644
index 00000000000..2e191fab806
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/postman-collection/postman.mustache
@@ -0,0 +1,74 @@
+{
+ "info": {
+ "name": "{{{appName}}}",
+ "description": {
+ "content": "{{{formattedDescription}}}",
+ "type": "text/markdown"
+ },
+ "version": "{{{appVersion}}}",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+ },
+ "item": [
+ {{#codegenOperationsByTag}}
+ {{#entrySet}}
+ {
+ "name": "{{key}}",
+ "item": [{{#value}}
+ {{>item}}{{^-last}},{{/-last}}{{/value}}
+ ]
+ }{{^-last}},{{/-last}}
+ {{/entrySet}}
+ {{/codegenOperationsByTag}}
+ {{#codegenOperationsList}}
+ {{>item}}{{^-last}},{{/-last}}
+ {{/codegenOperationsList}}
+ ],
+ {{#authMethods}}{{#-first}}{{#isApiKey}}"auth": {
+ "type": "apikey",
+ "apikey": [
+ {
+ "key": "value",
+ "value": "{{=<% %>=}}{{<%={{ }}=%>{{keyParamName}}{{=<% %>=}}}}<%={{ }}=%>",
+ "type": "string"
+ },
+ {
+ "key": "key",
+ "value": "{{keyParamName}}",
+ "type": "string"
+ }
+ ]
+ },{{/isApiKey}}{{#isBasic}}"auth": {
+ "type": "basic",
+ "basic": [
+ {
+ "key": "username",
+ "value": "{{=<% %>=}}{{<%={{ }}=%>USERNAME{{=<% %>=}}}}<%={{ }}=%>",
+ "type": "string"
+ },
+ {
+ "key": "password",
+ "value": "{{=<% %>=}}{{<%={{ }}=%>PASSWORD{{=<% %>=}}}}<%={{ }}=%>",
+ "type": "string"
+ }
+ ]
+ },{{/isBasic}}{{/-first}}{{/authMethods}}
+ "variable": [{{#servers}}{{#-first}}
+ {
+ "key": "baseUrl",
+ "value": "{{url}}",
+ "type": "string"
+ }{{/-first}}{{/servers}}{{#authMethods}}{{#isApiKey}},
+ {
+ "key": "{{keyParamName}}",
+ "value": "",
+ "type": "string"
+ }{{/isApiKey}}{{/authMethods}}{{#apiInfo}}{{#apis}}{{#vendorExtensions}}{{#-first}}{{#variables}}{{#-first}},{{/-first}}
+ {
+ {{! use first element in vendorExtensions }}
+ "key": "{{name}}",
+ "value": "{{example}}",
+ "type": "{{type}}"
+ }{{^-last}},{{/-last}}{{/variables}}{{/-first}}{{/vendorExtensions}}{{/apis}}{{/apiInfo}}
+ ]
+}
+
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/postman/PostmanCollectionCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/postman/PostmanCollectionCodegenTest.java
new file mode 100644
index 00000000000..35e057ff159
--- /dev/null
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/postman/PostmanCollectionCodegenTest.java
@@ -0,0 +1,646 @@
+package org.openapitools.codegen.postman;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Assert;
+import org.junit.Test;
+import org.openapitools.codegen.ClientOptInput;
+import org.openapitools.codegen.CodegenParameter;
+import org.openapitools.codegen.CodegenProperty;
+import org.openapitools.codegen.DefaultGenerator;
+import org.openapitools.codegen.config.CodegenConfigurator;
+import org.openapitools.codegen.languages.PostmanCollectionCodegen;
+
+import java.io.File;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.openapitools.codegen.TestUtils.*;
+
+public class PostmanCollectionCodegenTest {
+
+ @Test
+ public void testInitialConfigValues() throws Exception {
+ final PostmanCollectionCodegen postmanCollectionCodegen = new PostmanCollectionCodegen();
+ postmanCollectionCodegen.processOpts();
+
+ Assert.assertEquals(postmanCollectionCodegen.folderStrategy, "Tags");
+ Assert.assertEquals(postmanCollectionCodegen.postmanFile, "postman.json");
+
+ Assert.assertNull(postmanCollectionCodegen.additionalProperties().get("codegenOperationsList"));
+ Assert.assertNotNull(postmanCollectionCodegen.additionalProperties().get("codegenOperationsByTag"));
+ }
+
+ @Test
+ public void testConfigWithFolderStrategyTags() throws Exception {
+ final PostmanCollectionCodegen postmanCollectionCodegen = new PostmanCollectionCodegen();
+
+ postmanCollectionCodegen.additionalProperties().put(postmanCollectionCodegen.FOLDER_STRATEGY, "Tags");
+ postmanCollectionCodegen.processOpts();
+
+ Assert.assertEquals(postmanCollectionCodegen.folderStrategy, "Tags");
+
+ Assert.assertNull(postmanCollectionCodegen.additionalProperties().get("codegenOperationsList"));
+ Assert.assertNotNull(postmanCollectionCodegen.additionalProperties().get("codegenOperationsByTag"));
+ }
+
+ @Test
+ public void testBasicGeneration() throws IOException {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/Basic.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+ assertFileContains(path, "\"schema\": \"https://schema.getpostman.com/json/collection/v2.1.0/collection.json\"");
+
+ // verify request name (from summary)
+ assertFileContains(path, "\"name\": \"Get User\"");
+
+ }
+
+ @Test
+ public void testBasicGenerationJson() throws IOException {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/BasicJson.json")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+ assertFileContains(path, "\"schema\": \"https://schema.getpostman.com/json/collection/v2.1.0/collection.json\"");
+ }
+
+ @Test
+ public void testValidatePostmanJson() throws IOException {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/SampleProject.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ files.forEach(File::deleteOnExit);
+
+ final ObjectMapper mapper = new ObjectMapper();
+ mapper.readTree(new File(output + "/postman.json"));
+
+ }
+
+ @Test
+ public void testVariables() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/SampleProject.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ files.forEach(File::deleteOnExit);
+
+ assertFileExists(Paths.get(output + "/postman.json"));
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonNode = objectMapper.readTree(new File(output + "/postman.json"));
+ // verify json has variables
+ assertTrue(jsonNode.get("variable") instanceof ArrayNode);
+ assertEquals(5, ((ArrayNode) jsonNode.get("variable")).size());
+ }
+
+ @Test
+ public void testVariablesInRequestExample() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/BasicVariablesInExample.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonNode = objectMapper.readTree(new File(output + "/postman.json"));
+ // verify json has variables
+ assertTrue(jsonNode.get("variable") instanceof ArrayNode);
+ assertEquals(4, ((ArrayNode) jsonNode.get("variable")).size());
+
+ assertFileContains(path, "{{MY_VAR_NAME}}");
+
+ }
+
+ @Test
+ public void testSkipPostmanVariables() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .addAdditionalProperty(PostmanCollectionCodegen.POSTMAN_VARIABLES, false)
+ .setInputSpec("src/test/resources/3_0/postman-collection/BasicVariablesInExample.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonNode = objectMapper.readTree(new File(output + "/postman.json"));
+ // verify json has variables
+ assertTrue(jsonNode.get("variable") instanceof ArrayNode);
+ assertEquals(2, ((ArrayNode) jsonNode.get("variable")).size());
+ }
+
+ @Test
+ public void testGenerateWithoutPathParamsVariables() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .addAdditionalProperty(PostmanCollectionCodegen.PATH_PARAMS_AS_VARIABLES, false)
+ .setInputSpec("src/test/resources/3_0/postman-collection/SampleProject.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(configurator.toClientOptInput()).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ assertFileExists(Paths.get(output + "/postman.json"));
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonNode = objectMapper.readTree(new File(output + "/postman.json"));
+ // verify json has variables
+ assertTrue(jsonNode.get("variable") instanceof ArrayNode);
+ assertEquals(4, ((ArrayNode) jsonNode.get("variable")).size());
+ }
+
+ @Test
+ public void testComponentExamples() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/SampleProject.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+ // verify response body comes from components/examples
+ assertFileContains(path, "\"name\": \"Example request for Get User\"");
+ assertFileContains(path, "\"raw\": \"{\\n \\\"id\\\" : 777,\\n \\\"firstName\\\" : \\\"Alotta\\\",\\n \\\"lastName\\\" : \\\"Rotta\\\",\\n ");
+ }
+
+ @Test
+ public void testNamingRequestsWithUrl() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/SampleProject.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+ // verify request name (from path)
+ assertFileContains(path, "\"name\": \"/users/{{userId}}\"");
+ }
+
+ @Test
+ public void testExampleFromSchema() throws IOException, Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .addAdditionalProperty(PostmanCollectionCodegen.REQUEST_PARAMETER_GENERATION, "Schema")
+ .setInputSpec("src/test/resources/3_0/postman-collection/SampleProject.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(configurator.toClientOptInput()).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+ // verify request name (from path)
+ assertFileContains(path, "{\\n \\\"firstName\\\": \\\"\\\",\\n \\\"lastName\\\": \\\"\\\",\\n \\\"email\\\": \\\"\\\",\\n \\\"dateOfBirth\\\": \\\"\\\"\\n}");
+
+ }
+
+ @Test
+ public void testSecuritySchemes() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/SampleProject.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+ // check auth basic (1st security scheme in OpenAPI file)
+ assertFileContains(path, "\"auth\": { \"type\": \"basic\", \"basic\": [");
+ // check auth apiKey NOT found
+ assertFileNotContains(path, "\"auth\": { \"type\": \"apikey\", \"apikey\": [");
+ }
+
+ @Test
+ public void doubleCurlyBraces() {
+ String str = "/api/{var}/archive";
+
+ assertEquals("/api/{{var}}/archive", new PostmanCollectionCodegen().doubleCurlyBraces(str));
+ }
+
+ @Test
+ public void doubleCurlyBracesNoChanges() {
+ String str = "/api/{{var}}/archive";
+
+ assertEquals("/api/{{var}}/archive", new PostmanCollectionCodegen().doubleCurlyBraces(str));
+ }
+
+ @Test
+ public void extractExampleByName() {
+ String str = "#/components/examples/get-user-basic";
+
+ assertEquals("get-user-basic", new PostmanCollectionCodegen().extractExampleByName(str));
+ }
+
+ @Test
+ public void mapToPostmanType() {
+ assertEquals("string", new PostmanCollectionCodegen().mapToPostmanType("String"));
+ assertEquals("number", new PostmanCollectionCodegen().mapToPostmanType("integer"));
+ assertEquals("any", new PostmanCollectionCodegen().mapToPostmanType("object"));
+ }
+
+ @Test
+ public void testJsonExampleIncludingValueWithCommas() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/JsonWithCommasInJsonExample.json")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+ // check value with commas within quotes
+ assertFileContains(path, "\\\"acceptHeader\\\" : \\\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\\\"");
+ }
+
+ @Test
+ public void testDeprecatedEndpoint() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/SampleProject.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(configurator.toClientOptInput()).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+ // verify request name (from path)
+ assertFileContains(path, "(DEPRECATED)");
+ }
+
+ @Test
+ public void testGeneratedVariables() throws Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .setInputSpec("src/test/resources/3_0/postman-collection/BasicVariablesInExample.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+
+ assertFileContains(path, "\\\"createDate\\\" : \\\"{{$guid}}\\\"");
+ assertFileContains(path, "\\\"dateOfBirth\\\" : \\\"{{$isoTimestamp}}\\\"");
+
+ }
+
+ @Test
+ public void testSkipGeneratedVariables() throws IOException, Exception {
+
+ File output = Files.createTempDirectory("postmantest_").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("postman-collection")
+ .addAdditionalProperty(PostmanCollectionCodegen.POSTMAN_GUID, false)
+ .addAdditionalProperty(PostmanCollectionCodegen.POSTMAN_ISO_TIMESTAMP, false)
+ .setInputSpec("src/test/resources/3_0/postman-collection/BasicVariablesInExample.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ List files = generator.opts(clientOptInput).generate();
+
+ System.out.println(files);
+ files.forEach(File::deleteOnExit);
+
+ Path path = Paths.get(output + "/postman.json");
+ assertFileExists(path);
+
+ assertFileNotContains(path, "\\\"createDate\\\" : \\\"{{$guid}}\\\"");
+ assertFileNotContains(path, "\\\"dateOfBirth\\\" : \\\"{{$isoTimestamp}}\\\"");
+
+ }
+
+ @Test
+ public void testFormatDescription() {
+
+ final String DESCRIPTION = "## Description \n\n Text with markdown \n";
+ final String EXPECTED = "## Description \\n\\n Text with markdown \\n";
+
+ assertEquals(EXPECTED, new PostmanCollectionCodegen().formatDescription(DESCRIPTION));
+ }
+
+ @Test
+ public void testExtractPlaceholders() {
+ final String INPUT = "Input with {{placeholder_1}} and {{placeholder_2}}";
+
+ assertEquals(2, new PostmanCollectionCodegen().extractPlaceholders(INPUT).size());
+ }
+
+ @Test
+ public void testExtractWithDuplicatePlaceholders() {
+ final String INPUT = "Input with {{placeholder_1}}, {{placeholder_2}} and again {{placeholder_2}}";
+
+ assertEquals(2, new PostmanCollectionCodegen().extractPlaceholders(INPUT).size());
+ }
+
+ @Test
+ public void testExtractPlaceholdersIncludingGuidFormula() {
+ final String INPUT = "Input with {{placeholder_1}} and {{$guid}}";
+
+ assertEquals(1, new PostmanCollectionCodegen().extractPlaceholders(INPUT).size());
+ }
+
+ @Test
+ public void testIsPostmanDynamicVariable() {
+ assertTrue(new PostmanCollectionCodegen().isPostmanDynamicVariable("$guid"));
+ }
+
+ // test helpers
+ @Test
+ public void getPostmanTypeNumber() {
+ CodegenProperty codegenProperty = new CodegenProperty();
+ codegenProperty.isNumeric = true;
+
+ assertEquals("number", new PostmanCollectionCodegen().getPostmanType(codegenProperty));
+ }
+
+ @Test
+ public void getPostmanTypeDate() {
+ CodegenProperty codegenProperty = new CodegenProperty();
+ codegenProperty.isDate = true;
+
+ assertEquals("date", new PostmanCollectionCodegen().getPostmanType(codegenProperty));
+ }
+
+ @Test
+ public void getPostmanTypeString() {
+ CodegenProperty codegenProperty = new CodegenProperty();
+ codegenProperty.isString = true;
+
+ assertEquals("string", new PostmanCollectionCodegen().getPostmanType(codegenProperty));
+ }
+
+ @Test
+ public void getExampleFromSchema() {
+ final String EXPECTED = "{\\n \\\"firstname\\\": \\\"\\\",\\n \\\"lastname\\\": \\\"\\\",\\n \\\"age\\\": \\\"\\\",\\n \\\"birthDate\\\": \\\"\\\"\\n}";
+
+ CodegenParameter codegenParameter = new CodegenParameter();
+ codegenParameter.vars.add(new CodegenProperty() {{
+ baseName = "firstname";
+ isString = true;
+ }});
+ codegenParameter.vars.add(new CodegenProperty() {{
+ baseName = "lastname";
+ isString = true;
+ }});
+ codegenParameter.vars.add(new CodegenProperty() {{
+ baseName = "age";
+ isNumeric = true;
+ }});
+ codegenParameter.vars.add(new CodegenProperty() {{
+ baseName = "birthDate";
+ isDate = true;
+ }});
+
+ assertEquals(EXPECTED, new PostmanCollectionCodegen().getJsonFromSchema(codegenParameter));
+ }
+
+ @Test
+ public void formatJson() {
+
+ final String EXPECTED = "{\\n \\\"id\\\" : 1,\\n \\\"city\\\" : \\\"Amsterdam\\\"\\n}";
+ final String JSON = "{\"id\":1,\"city\":\"Amsterdam\"}";
+
+ assertEquals(EXPECTED, new PostmanCollectionCodegen().formatJson(JSON));
+
+ }
+
+ @Test
+ public void formatJsonIncludingCommas() {
+
+ final String EXPECTED = "{\\n \\\"id\\\" : 1,\\n \\\"list\\\" : \\\"AMS,LON,ROM\\\"\\n}";
+ final String JSON = "{\"id\":1,\"list\":\"AMS,LON,ROM\"}";
+
+ assertEquals(EXPECTED, new PostmanCollectionCodegen().formatJson(JSON));
+
+ }
+
+ @Test
+ public void getAttributesFromJson() {
+
+ final String JSON = "{\"id\":1,\"list\":\"AMS,LON,ROM\"}";
+ assertEquals(2, new PostmanCollectionCodegen().getAttributes(JSON).length);
+
+ }
+
+ @Test
+ public void convertObjectNodeToJson() {
+
+ final String EXPECTED = "{\\n \\\"id\\\" : 1,\\n \\\"city\\\" : \\\"Amsterdam\\\"\\n}";
+
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode city = mapper.createObjectNode();
+
+ city.put("id", 1);
+ city.put("city", "Amsterdam");
+
+ assertEquals(EXPECTED, new PostmanCollectionCodegen().convertToJson(city));
+
+ }
+
+ @Test
+ public void convertObjectNodeIncludingDoubleQuoteToJson() {
+
+ final String EXPECTED = "{\\n \\\"id\\\" : 1,\\n \\\"city\\\" : \\\"it is \\\\\"Amsterdam\\\\\" \\\"\\n}";
+
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode city = mapper.createObjectNode();
+
+ city.put("id", 1);
+ city.put("city", "it is \"Amsterdam\" ");
+
+ assertEquals(EXPECTED, new PostmanCollectionCodegen().convertToJson(city));
+
+ }
+
+ @Test
+ public void convertLinkedHashMapToJson() {
+
+ final String EXPECTED = "{\\n \\\"id\\\": 1,\\n \\\"city\\\": \\\"Amsterdam\\\"\\n}";
+
+ LinkedHashMap city = new LinkedHashMap<>();
+ city.put("id", 1);
+ city.put("city", "Amsterdam");
+
+ assertEquals(EXPECTED, new PostmanCollectionCodegen().convertToJson(city));
+
+ }
+
+ @Test
+ public void convertNestedLinkedHashMapToJson() {
+
+ final String EXPECTED =
+ "{\\n " +
+ "\\\"id\\\": 1,\\n \\\"city\\\": \\\"Amsterdam\\\",\\n " +
+ "\\\"country\\\": {\\n \\\"id\\\": 2,\\n \\\"code\\\": \\\"NL\\\"\\n}" +
+ "\\n}";
+
+ LinkedHashMap city = new LinkedHashMap<>();
+ city.put("id", 1);
+ city.put("city", "Amsterdam");
+ LinkedHashMap country = new LinkedHashMap<>();
+ country.put("id", 2);
+ country.put("code", "NL");
+ city.put("country", country);
+
+ assertEquals(EXPECTED, new PostmanCollectionCodegen().convertToJson(city));
+
+ }
+
+}
diff --git a/modules/openapi-generator/src/test/resources/3_0/postman-collection/Basic.yaml b/modules/openapi-generator/src/test/resources/3_0/postman-collection/Basic.yaml
new file mode 100644
index 00000000000..16c039b515d
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/postman-collection/Basic.yaml
@@ -0,0 +1,106 @@
+openapi: 3.0.0
+info:
+ title: Basic
+ version: '1.0'
+ description: Sample API
+ license:
+ name: Apache 2.0
+ url: 'https://www.apache.org/licenses/LICENSE-2.0'
+servers:
+ - url: 'http://localhost:5001'
+ description: dev server
+ - url: 'http://localhost:5001'
+ description: test server
+paths:
+ '/users/{userId}':
+ get:
+ summary: Get User
+ description: Get User Info by User ID
+ operationId: get-users-userId
+ tags:
+ - basic
+ parameters:
+ - description: Unique identifier of the user
+ name: userId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: User Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ examples:
+ Get User Alice Smith (json):
+ value:
+ id: 142
+ firstName: Alice
+ lastName: Smith
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ signUpDate: '2019-08-24'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ examples:
+ Get User Alice Smith (xml):
+ value:
+ id: 143
+ firstName: Alice
+ lastName: Smith
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ signUpDate: '2019-08-24'
+ '404':
+ description: User Not Found
+components:
+ schemas:
+ User:
+ title: User
+ type: object
+ description: ''
+ x-examples:
+ Alice Smith:
+ id: 144
+ firstName: Alice
+ lastName: Smith
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ signUpDate: '2019-08-24'
+ properties:
+ id:
+ type: integer
+ description: Unique identifier for the given user.
+ firstName:
+ type: string
+ lastName:
+ type: string
+ email:
+ type: string
+ format: email
+ dateOfBirth:
+ type: string
+ format: date
+ example: '1997-10-31'
+ emailVerified:
+ type: boolean
+ description: Set to true if the user's email has been verified.
+ createDate:
+ type: string
+ format: date
+ description: The date that the user was created.
+ required:
+ - id
+ - firstName
+ - lastName
+ - email
+ - emailVerified
+tags:
+ - name: basic
+ description: Basic tag
diff --git a/modules/openapi-generator/src/test/resources/3_0/postman-collection/BasicJson.json b/modules/openapi-generator/src/test/resources/3_0/postman-collection/BasicJson.json
new file mode 100644
index 00000000000..d59aaaa62ab
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/postman-collection/BasicJson.json
@@ -0,0 +1,167 @@
+{
+ "openapi" : "3.0.0",
+ "info" : {
+ "description" : "Sample API",
+ "license" : {
+ "name" : "Apache 2.0",
+ "url" : "https://www.apache.org/licenses/LICENSE-2.0"
+ },
+ "title" : "Basic",
+ "version" : "1.0"
+ },
+ "servers" : [ {
+ "description" : "dev server",
+ "url" : "http://localhost:{port}/{version}",
+ "variables": {
+ "version": {
+ "default": "v1",
+ "description": "version of the API"
+ },
+ "port": {
+ "enum": [
+ "5000",
+ "8080"
+ ],
+ "default": "5000"
+ }
+ }
+ }, {
+ "description" : "test server",
+ "url" : "http://localhost:{port}/{version}",
+ "variables": {
+ "version": {
+ "default": "v1",
+ "description": "version of the API"
+ },
+ "port": {
+ "enum": [
+ "5000",
+ "8080"
+ ],
+ "default": "5000"
+ }
+ }
+ } ],
+ "tags" : [ {
+ "description" : "Basic tag",
+ "name" : "basic"
+ } ],
+ "paths" : {
+ "/users/{userId}" : {
+ "get" : {
+ "description" : "Get User Info by User ID",
+ "operationId" : "get-users-userId",
+ "parameters" : [ {
+ "description" : "Unique identifier of the user",
+ "explode" : false,
+ "in" : "path",
+ "name" : "userId",
+ "required" : true,
+ "schema" : {
+ "type" : "string"
+ },
+ "style" : "simple"
+ } ],
+ "responses" : {
+ "200" : {
+ "content" : {
+ "application/json" : {
+ "examples" : {
+ "Get User Alice Smith (json)" : {
+ "value" : {
+ "id" : 142,
+ "firstName" : "Alice",
+ "lastName" : "Smith",
+ "email" : "alice.smith@gmail.com",
+ "dateOfBirth" : "1997-10-31",
+ "emailVerified" : true,
+ "signUpDate" : "2019-08-24"
+ }
+ }
+ },
+ "schema" : {
+ "$ref" : "#/components/schemas/User"
+ }
+ },
+ "application/xml" : {
+ "examples" : {
+ "Get User Alice Smith (xml)" : {
+ "value" : {
+ "id" : 143,
+ "firstName" : "Alice",
+ "lastName" : "Smith",
+ "email" : "alice.smith@gmail.com",
+ "dateOfBirth" : "1997-10-31",
+ "emailVerified" : true,
+ "signUpDate" : "2019-08-24"
+ }
+ }
+ },
+ "schema" : {
+ "$ref" : "#/components/schemas/User"
+ }
+ }
+ },
+ "description" : "User Found"
+ },
+ "404" : {
+ "description" : "User Not Found"
+ }
+ },
+ "summary" : "Get User",
+ "tags" : [ "basic" ]
+ }
+ }
+ },
+ "components" : {
+ "schemas" : {
+ "User" : {
+ "description" : "",
+ "properties" : {
+ "id" : {
+ "description" : "Unique identifier for the given user.",
+ "type" : "integer"
+ },
+ "firstName" : {
+ "type" : "string"
+ },
+ "lastName" : {
+ "type" : "string"
+ },
+ "email" : {
+ "format" : "email",
+ "type" : "string"
+ },
+ "dateOfBirth" : {
+ "example" : "1997-10-31",
+ "format" : "date",
+ "type" : "string"
+ },
+ "emailVerified" : {
+ "description" : "Set to true if the user's email has been verified.",
+ "type" : "boolean"
+ },
+ "createDate" : {
+ "description" : "The date that the user was created.",
+ "format" : "date",
+ "type" : "string"
+ }
+ },
+ "required" : [ "email", "emailVerified", "firstName", "id", "lastName" ],
+ "title" : "User",
+ "type" : "object",
+ "x-examples" : {
+ "Alice Smith" : {
+ "id" : 144,
+ "firstName" : "Alice",
+ "lastName" : "Smith",
+ "email" : "alice.smith@gmail.com",
+ "dateOfBirth" : "1997-10-31",
+ "emailVerified" : true,
+ "signUpDate" : "2019-08-24"
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/test/resources/3_0/postman-collection/BasicVariablesInExample.yaml b/modules/openapi-generator/src/test/resources/3_0/postman-collection/BasicVariablesInExample.yaml
new file mode 100644
index 00000000000..d0d5988c351
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/postman-collection/BasicVariablesInExample.yaml
@@ -0,0 +1,116 @@
+openapi: 3.0.0
+info:
+ title: BasicExample
+ version: '1.0'
+ description: Sample API
+ license:
+ name: Apache 2.0
+ url: 'https://www.apache.org/licenses/LICENSE-2.0'
+servers:
+ - url: 'http://localhost:5001'
+ description: dev server
+ - url: 'http://localhost:5001'
+ description: test server
+paths:
+ '/users/{userId}':
+ patch:
+ summary: Patch User
+ description: Update User Info
+ operationId: patch-users-userId
+ tags:
+ - basic
+ parameters:
+ - description: Unique identifier of the user
+ name: userId
+ in: path
+ required: true
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/json:
+ examples:
+ patch-user:
+ $ref: '#/components/examples/patch-user-example'
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ '200':
+ description: User Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ examples:
+ Get User Alice Smith (json):
+ value:
+ id: 142
+ firstName: Alice
+ lastName: Smith
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ signUpDate: '2019-08-24'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ examples:
+ Get User Alice Smith (xml):
+ value:
+ id: 143
+ firstName: Alice
+ lastName: Smith
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ signUpDate: '2019-08-24'
+ '404':
+ description: User Not Found
+components:
+ schemas:
+ User:
+ title: User
+ type: object
+ description: ''
+ properties:
+ id:
+ type: integer
+ description: Unique identifier for the given user.
+ firstName:
+ type: string
+ lastName:
+ type: string
+ email:
+ type: string
+ format: email
+ dateOfBirth:
+ type: string
+ format: date
+ emailVerified:
+ type: boolean
+ description: Set to true if the user's email has been verified.
+ createDate:
+ type: string
+ format: date
+ description: The date that the user was created.
+ required:
+ - id
+ - firstName
+ - lastName
+ - email
+ - emailVerified
+ examples:
+ patch-user-example:
+ summary: Example patch user
+ value:
+ id: 001
+ firstName: "{{MY_VAR_NAME}}"
+ lastName: "{{MY_VAR_LAST_NAME}}"
+ email: alotta.rotta@gmail.com
+ dateOfBirth: "{{ISO_TIMESTAMP}}"
+ emailVerified: true
+ createDate: "{{UNIQUE_REFERENCE}}"
+
+tags:
+ - name: basic
+ description: Basic tag
diff --git a/modules/openapi-generator/src/test/resources/3_0/postman-collection/JsonWithCommasInJsonExample.json b/modules/openapi-generator/src/test/resources/3_0/postman-collection/JsonWithCommasInJsonExample.json
new file mode 100644
index 00000000000..f7ee7af0bdc
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/postman-collection/JsonWithCommasInJsonExample.json
@@ -0,0 +1,75 @@
+{
+ "openapi" : "3.0.0",
+ "info" : {
+ "description" : "Sample API",
+ "title" : "Basic",
+ "version" : "1.0"
+ },
+ "tags" : [ {
+ "description" : "Basic tag",
+ "name" : "basic"
+ } ],
+ "paths" : {
+ "/ws" : {
+ "post" : {
+ "description" : "Create",
+ "operationId" : "ws-post",
+ "requestBody" : {
+ "content" : {
+ "application/json" : {
+ "examples" : {
+ "basic" : {
+ "$ref" : "#/components/examples/ex-1"
+ }
+ },
+ "schema" : {
+ "$ref" : "#/components/schemas/Item"
+ }
+ }
+ }
+ },
+ "responses" : {
+ "200" : {
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/Item"
+ }
+ }
+ },
+ "description" : "Item created"
+ }
+ },
+ "summary" : "Create",
+ "tags" : [ "basic" ]
+ }
+ }
+ },
+ "components" : {
+ "schemas" : {
+ "Item" : {
+ "description" : "",
+ "properties" : {
+ "id" : {
+ "description" : "Item id",
+ "type" : "integer"
+ },
+ "acceptHeader" : {
+ "type" : "string"
+ }
+ },
+ "title" : "item",
+ "type" : "object"
+ }
+ },
+ "examples": {
+ "ex-1": {
+ "summary" : "Example 1",
+ "value" : {
+ "id": 1,
+ "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/test/resources/3_0/postman-collection/SampleProject.yaml b/modules/openapi-generator/src/test/resources/3_0/postman-collection/SampleProject.yaml
new file mode 100644
index 00000000000..cfe38e97bd9
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/postman-collection/SampleProject.yaml
@@ -0,0 +1,310 @@
+openapi: 3.0.0
+info:
+ title: Sample project
+ version: '1.0'
+ description: 'Sample API Check "API Key" '
+ license:
+ name: Apache 2.0
+ url: 'https://www.apache.org/licenses/LICENSE-2.0'
+servers:
+ - url: 'http://localhost:{port}/{version}'
+ description: dev server
+ variables:
+ port:
+ description: Port number
+ enum:
+ - '5000'
+ - '8080'
+ default: '5000'
+ version:
+ default: v1
+ description: API version
+ - url: 'http://localhost:{port}/{version}'
+ description: test server
+ variables:
+ port:
+ description: Port number
+ enum:
+ - '5000'
+ - '8080'
+ default: '5000'
+ version:
+ default: v1
+ description: API version
+paths:
+ '/users/':
+ get:
+ summary: Get User Info by Query Param
+ operationId: get-users-query-id
+ description: Retrieve the information of the user with the matching user ID.
+ tags:
+ - basic
+ parameters:
+ - description: Query Id.
+ name: pUserId
+ in: query
+ required: true
+ schema:
+ type: string
+ example: 888
+
+ responses:
+ '200':
+ description: User Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ example:
+ id: schema-example
+ firstName: Alice
+ lastName: Smith333
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ signUpDate: '2019-08-24'
+ examples:
+ Get User Alice Smith:
+ value:
+ id: 142
+ firstName: Alice
+ lastName: Smith
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ signUpDate: '2019-08-24'
+ Get User Phil Smith:
+ value:
+ id: 143
+ firstName: Phil
+ lastName: Smith
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ signUpDate: '2019-08-24'
+ '404':
+ description: User Not Found
+ '/users/{userId}':
+ parameters:
+ - schema:
+ type: integer
+ examples:
+ a:
+ value: a
+ summary: a summary
+ b:
+ value: b
+ summary: b summary
+ name: userId
+ in: path
+ required: true
+ description: Id of an existing user.
+ - schema:
+ type: string
+ default: code_one
+ name: strCode
+ in: header
+ description: Code as header
+ - schema:
+ type: string
+ name: strCode2
+ in: header
+ description: Code as header2
+ get:
+ summary: Get User Info by User ID
+ tags:
+ - advanced
+ responses:
+ '200':
+ description: User Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ example:
+ id: 9998
+ firstName: Alice9998 resp example
+ lastName: Smith9998
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ createDate: '2019-08-24'
+ '404':
+ description: User Not Found
+ operationId: get-users-userId
+ description: Retrieve the information of the user with the matching user ID.
+ patch:
+ summary: Update User Information
+ deprecated: true
+ operationId: patch-users-userId
+ responses:
+ '200':
+ description: User Updated
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ examples:
+ Updated User Rebecca Baker:
+ value:
+ id: 13
+ firstName: Rebecca
+ lastName: Baker
+ email: rebecca@gmail.com
+ dateOfBirth: '1985-10-02'
+ emailVerified: false
+ createDate: '2019-08-24'
+ '404':
+ description: User Not Found
+ '409':
+ description: Email Already Taken
+ description: Update the information of an existing user.
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ firstName:
+ type: string
+ lastName:
+ type: string
+ email:
+ type: string
+ description: >-
+ If a new email is given, the user's email verified property
+ will be set to false.
+ dateOfBirth:
+ type: string
+ examples:
+ Update First Name:
+ value:
+ firstName: Rebecca
+ Update Email:
+ value:
+ email: rebecca@gmail.com
+ Update Last Name & Date of Birth:
+ value:
+ lastName: Baker
+ dateOfBirth: '1985-10-02'
+ description: Patch user properties to update.
+ /user:
+ post:
+ summary: Create New User
+ operationId: post-user
+ responses:
+ '200':
+ description: User Created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ examples:
+ basic:
+ $ref: '#/components/examples/get-user-basic'
+ '400':
+ description: Missing Required Information
+ '409':
+ description: Email Already Taken
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ firstName:
+ type: string
+ lastName:
+ type: string
+ email:
+ type: string
+ dateOfBirth:
+ type: string
+ format: date
+ required:
+ - firstName
+ - lastName
+ - email
+ - dateOfBirth
+ examples:
+ basic:
+ $ref: '#/components/examples/get-user-basic'
+ description: Post the necessary fields for the API to create a new user.
+ description: Create a new user.
+ tags:
+ - basic
+components:
+ securitySchemes:
+ BasicAuth:
+ type: http
+ scheme: basic
+ BearerAuth:
+ type: http
+ scheme: bearer
+ ApiKeyAuth:
+ type: apiKey
+ name: X-API-Key
+ in: header
+ schemas:
+ User:
+ title: User
+ type: object
+ description: ''
+ example:
+ id: 999
+ firstName: Alice9 schema example
+ lastName: Smith9
+ email: alice.smith@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ createDate: '2019-08-24'
+ properties:
+ id:
+ type: integer
+ description: Unique identifier for the given user.
+ example: 0
+ firstName:
+ type: string
+ example: Alix
+ lastName:
+ type: string
+ example: Smith
+ email:
+ type: string
+ format: email
+ example: alix.smith@gmail.com
+ dateOfBirth:
+ type: string
+ format: date
+ example: '1997-10-31'
+ emailVerified:
+ type: boolean
+ description: Set to true if the user's email has been verified.
+ example: true
+ createDate:
+ type: string
+ format: date
+ description: The date that the user was created.
+ example: '2019-08-24'
+ required:
+ - id
+ - firstName
+ - lastName
+ - email
+ - emailVerified
+ examples:
+ get-user-basic:
+ summary: Example request for Get User
+ value:
+ id: 777
+ firstName: Alotta
+ lastName: Rotta
+ email: alotta.rotta@gmail.com
+ dateOfBirth: '1997-10-31'
+ emailVerified: true
+ createDate: '2019-08-24'
+tags:
+ - name: basic
+ description: Basic tag
+ - name: advanced
+ description: Advanced tag
diff --git a/samples/documentation/postman-collection/.openapi-generator-ignore b/samples/documentation/postman-collection/.openapi-generator-ignore
new file mode 100644
index 00000000000..7484ee590a3
--- /dev/null
+++ b/samples/documentation/postman-collection/.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/documentation/postman-collection/.openapi-generator/FILES b/samples/documentation/postman-collection/.openapi-generator/FILES
new file mode 100644
index 00000000000..64a1c0bf910
--- /dev/null
+++ b/samples/documentation/postman-collection/.openapi-generator/FILES
@@ -0,0 +1 @@
+postman.json
diff --git a/samples/documentation/postman-collection/.openapi-generator/VERSION b/samples/documentation/postman-collection/.openapi-generator/VERSION
new file mode 100644
index 00000000000..ba8a874deab
--- /dev/null
+++ b/samples/documentation/postman-collection/.openapi-generator/VERSION
@@ -0,0 +1 @@
+6.6.0-SNAPSHOT
\ No newline at end of file
diff --git a/samples/documentation/postman-collection/postman.json b/samples/documentation/postman-collection/postman.json
new file mode 100644
index 00000000000..f9c4e042eb9
--- /dev/null
+++ b/samples/documentation/postman-collection/postman.json
@@ -0,0 +1,275 @@
+{
+ "info": {
+ "name": "Sample project",
+ "description": {
+ "content": "Sample API Check \"API Key\" ",
+ "type": "text/markdown"
+ },
+ "version": "1.0",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+ },
+ "item": [
+ {
+ "name": "default",
+ "item": [
+ {
+ "name": "/users/{{userId}} (DEPRECATED)",
+ "description": "Update the information of an existing user.",
+ "item": [
+ {
+ "name": "Update User Information",
+ "request": {
+ "method": "PATCH",
+ "header": [
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Accept",
+ "value": "application/json"
+ },
+ {
+ "key": "strCode",
+ "value": "code_one"
+ },
+ {
+ "key": "strCode2",
+ "value": "null"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"firstName\" : \"Rebecca\"\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{baseUrl}}/users/{{userId}}",
+ "host": [
+ "{{baseUrl}}"
+ ],
+ "path": [
+ "users",
+ "{{userId}}"
+ ],
+ "variable": [
+ {
+ "key": "userId",
+ "value": "",
+ "description": "Id of an existing user."
+ }
+ ],
+ "query": [
+ ]
+ },
+ "description": "Update the information of an existing user."
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "advanced",
+ "item": [
+ {
+ "name": "/users/{{userId}}",
+ "description": "Retrieve the information of the user with the matching user ID.",
+ "item": [
+ {
+ "name": "Get User Info by User ID",
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "Accept",
+ "value": "application/json"
+ },
+ {
+ "key": "strCode",
+ "value": "code_one"
+ },
+ {
+ "key": "strCode2",
+ "value": "null"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{baseUrl}}/users/{{userId}}",
+ "host": [
+ "{{baseUrl}}"
+ ],
+ "path": [
+ "users",
+ "{{userId}}"
+ ],
+ "variable": [
+ {
+ "key": "userId",
+ "value": "",
+ "description": "Id of an existing user."
+ }
+ ],
+ "query": [
+ ]
+ },
+ "description": "Retrieve the information of the user with the matching user ID."
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "basic",
+ "item": [
+ {
+ "name": "/users/",
+ "description": "Retrieve the information of the user with the matching user ID.",
+ "item": [
+ {
+ "name": "Get User Info by Query Param",
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "Accept",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{baseUrl}}/users/",
+ "host": [
+ "{{baseUrl}}"
+ ],
+ "path": [
+ "users"
+ ],
+ "variable": [
+ ],
+ "query": [
+ {
+ "key": "pUserId",
+ "value": "888"
+ }
+ ]
+ },
+ "description": "Retrieve the information of the user with the matching user ID."
+ }
+ }
+ ]
+ },
+ {
+ "name": "/user",
+ "description": "Create a new user.",
+ "item": [
+ {
+ "name": "Example request for Get User",
+ "request": {
+ "method": "POST",
+ "header": [
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Accept",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"id\" : 777,\n \"firstName\" : \"Alotta\",\n \"lastName\" : \"Rotta\",\n \"email\" : \"alotta.rotta@gmail.com\",\n \"dateOfBirth\" : \"1997-10-31\",\n \"emailVerified\" : true,\n \"createDate\" : \"2019-08-24\"\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{baseUrl}}/user",
+ "host": [
+ "{{baseUrl}}"
+ ],
+ "path": [
+ "user"
+ ],
+ "variable": [
+ ],
+ "query": [
+ ]
+ },
+ "description": "Create a new user."
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "auth": {
+ "type": "basic",
+ "basic": [
+ {
+ "key": "username",
+ "value": "{{USERNAME}}",
+ "type": "string"
+ },
+ {
+ "key": "password",
+ "value": "{{PASSWORD}}",
+ "type": "string"
+ }
+ ]
+ },
+ "variable": [
+ {
+ "key": "baseUrl",
+ "value": "http://localhost:{port}/{version}",
+ "type": "string"
+ },
+ {
+ "key": "X-API-Key",
+ "value": "",
+ "type": "string"
+ },
+ {
+ "key": "version",
+ "value": "v1",
+ "type": "string"
+ },
+ {
+ "key": "port",
+ "value": "5000",
+ "type": "string"
+ },
+ {
+ "key": "userId",
+ "value": "a",
+ "type": "number"
+ }
+ ]
+}
+
diff --git a/samples/schema/postman-collection/.openapi-generator-ignore b/samples/schema/postman-collection/.openapi-generator-ignore
new file mode 100644
index 00000000000..7484ee590a3
--- /dev/null
+++ b/samples/schema/postman-collection/.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/schema/postman-collection/.openapi-generator/FILES b/samples/schema/postman-collection/.openapi-generator/FILES
new file mode 100644
index 00000000000..64a1c0bf910
--- /dev/null
+++ b/samples/schema/postman-collection/.openapi-generator/FILES
@@ -0,0 +1 @@
+postman.json
diff --git a/samples/schema/postman-collection/.openapi-generator/VERSION b/samples/schema/postman-collection/.openapi-generator/VERSION
new file mode 100644
index 00000000000..757e6740040
--- /dev/null
+++ b/samples/schema/postman-collection/.openapi-generator/VERSION
@@ -0,0 +1 @@
+7.0.0-SNAPSHOT
\ No newline at end of file
diff --git a/samples/schema/postman-collection/postman.json b/samples/schema/postman-collection/postman.json
new file mode 100644
index 00000000000..f9c4e042eb9
--- /dev/null
+++ b/samples/schema/postman-collection/postman.json
@@ -0,0 +1,275 @@
+{
+ "info": {
+ "name": "Sample project",
+ "description": {
+ "content": "Sample API Check \"API Key\" ",
+ "type": "text/markdown"
+ },
+ "version": "1.0",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+ },
+ "item": [
+ {
+ "name": "default",
+ "item": [
+ {
+ "name": "/users/{{userId}} (DEPRECATED)",
+ "description": "Update the information of an existing user.",
+ "item": [
+ {
+ "name": "Update User Information",
+ "request": {
+ "method": "PATCH",
+ "header": [
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Accept",
+ "value": "application/json"
+ },
+ {
+ "key": "strCode",
+ "value": "code_one"
+ },
+ {
+ "key": "strCode2",
+ "value": "null"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"firstName\" : \"Rebecca\"\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{baseUrl}}/users/{{userId}}",
+ "host": [
+ "{{baseUrl}}"
+ ],
+ "path": [
+ "users",
+ "{{userId}}"
+ ],
+ "variable": [
+ {
+ "key": "userId",
+ "value": "",
+ "description": "Id of an existing user."
+ }
+ ],
+ "query": [
+ ]
+ },
+ "description": "Update the information of an existing user."
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "advanced",
+ "item": [
+ {
+ "name": "/users/{{userId}}",
+ "description": "Retrieve the information of the user with the matching user ID.",
+ "item": [
+ {
+ "name": "Get User Info by User ID",
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "Accept",
+ "value": "application/json"
+ },
+ {
+ "key": "strCode",
+ "value": "code_one"
+ },
+ {
+ "key": "strCode2",
+ "value": "null"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{baseUrl}}/users/{{userId}}",
+ "host": [
+ "{{baseUrl}}"
+ ],
+ "path": [
+ "users",
+ "{{userId}}"
+ ],
+ "variable": [
+ {
+ "key": "userId",
+ "value": "",
+ "description": "Id of an existing user."
+ }
+ ],
+ "query": [
+ ]
+ },
+ "description": "Retrieve the information of the user with the matching user ID."
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "basic",
+ "item": [
+ {
+ "name": "/users/",
+ "description": "Retrieve the information of the user with the matching user ID.",
+ "item": [
+ {
+ "name": "Get User Info by Query Param",
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "Accept",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{baseUrl}}/users/",
+ "host": [
+ "{{baseUrl}}"
+ ],
+ "path": [
+ "users"
+ ],
+ "variable": [
+ ],
+ "query": [
+ {
+ "key": "pUserId",
+ "value": "888"
+ }
+ ]
+ },
+ "description": "Retrieve the information of the user with the matching user ID."
+ }
+ }
+ ]
+ },
+ {
+ "name": "/user",
+ "description": "Create a new user.",
+ "item": [
+ {
+ "name": "Example request for Get User",
+ "request": {
+ "method": "POST",
+ "header": [
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ {
+ "key": "Accept",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"id\" : 777,\n \"firstName\" : \"Alotta\",\n \"lastName\" : \"Rotta\",\n \"email\" : \"alotta.rotta@gmail.com\",\n \"dateOfBirth\" : \"1997-10-31\",\n \"emailVerified\" : true,\n \"createDate\" : \"2019-08-24\"\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{baseUrl}}/user",
+ "host": [
+ "{{baseUrl}}"
+ ],
+ "path": [
+ "user"
+ ],
+ "variable": [
+ ],
+ "query": [
+ ]
+ },
+ "description": "Create a new user."
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "auth": {
+ "type": "basic",
+ "basic": [
+ {
+ "key": "username",
+ "value": "{{USERNAME}}",
+ "type": "string"
+ },
+ {
+ "key": "password",
+ "value": "{{PASSWORD}}",
+ "type": "string"
+ }
+ ]
+ },
+ "variable": [
+ {
+ "key": "baseUrl",
+ "value": "http://localhost:{port}/{version}",
+ "type": "string"
+ },
+ {
+ "key": "X-API-Key",
+ "value": "",
+ "type": "string"
+ },
+ {
+ "key": "version",
+ "value": "v1",
+ "type": "string"
+ },
+ {
+ "key": "port",
+ "value": "5000",
+ "type": "string"
+ },
+ {
+ "key": "userId",
+ "value": "a",
+ "type": "number"
+ }
+ ]
+}
+