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" + } + ] +} +