Skip to content

Commit c22d790

Browse files
authored
[POSTMAN] Include response examples (#21073)
* Extract response examples * Add response examples to spec * Generate Postman samples * Test samples
1 parent ca1f025 commit c22d790

File tree

7 files changed

+758
-433
lines changed

7 files changed

+758
-433
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PostmanCollectionCodegen.java

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.*;
2525
import java.util.regex.Matcher;
2626
import java.util.regex.Pattern;
27+
import java.util.stream.Collectors;
2728

2829
/**
2930
* OpenAPI generator for Postman Collection format v2.1
@@ -389,12 +390,14 @@ List<PostmanRequestItem> getPostmanRequests(CodegenOperation codegenOperation) {
389390
String exampleRef = entry.getValue().get$ref();
390391
Example example = this.openAPI.getComponents().getExamples().get(extractExampleByName(exampleRef));
391392
String exampleAsString = getJsonFromExample(example);
393+
String exampleName = entry.getKey();
392394

393-
items.add(new PostmanRequestItem(example.getSummary(), exampleAsString));
395+
items.add(new PostmanRequestItem(exampleName, example.getSummary(), exampleAsString));
394396
} else if (entry.getValue().getValue() != null && entry.getValue().getValue() instanceof ObjectNode) {
395397
// find inline
396398
String exampleAsString = convertToJson((ObjectNode) entry.getValue().getValue());
397-
items.add(new PostmanRequestItem(entry.getKey(), exampleAsString));
399+
String exampleName = entry.getKey();
400+
items.add(new PostmanRequestItem(exampleName, entry.getKey(), exampleAsString));
398401
}
399402
}
400403
} else if (codegenOperation.bodyParam.example != null) {
@@ -416,6 +419,24 @@ List<PostmanRequestItem> getPostmanRequests(CodegenOperation codegenOperation) {
416419
items.add(new PostmanRequestItem(codegenOperation.summary, ""));
417420
}
418421

422+
// Grabbing responses
423+
List<CodegenResponse> responses = codegenOperation.responses;
424+
List<PostmanResponse> allPostmanResponses = new ArrayList<>();
425+
for (CodegenResponse response : responses) {
426+
List<PostmanResponse> postmanResponses = getResponseExamples(response, response.message);
427+
allPostmanResponses.addAll(postmanResponses);
428+
}
429+
430+
// Adding responses to corresponding requests
431+
for(PostmanRequestItem item: items){
432+
List<PostmanResponse> postmanResponses = allPostmanResponses.stream().filter( r -> Objects.equals(r.getId(), item.getId())).collect(Collectors.toList());
433+
if(!postmanResponses.isEmpty()){
434+
postmanResponses.forEach(r -> r.setOriginalRequest(item));
435+
item.addResponses(postmanResponses);
436+
}
437+
}
438+
439+
419440
return items;
420441
}
421442

@@ -454,6 +475,37 @@ List<PostmanRequestItem> setPostmanIsoTimestamp(List<PostmanRequestItem> postman
454475
return postmanRequests;
455476
}
456477

478+
List<PostmanResponse> getResponseExamples(CodegenResponse codegenResponse, String message) {
479+
List<PostmanResponse> postmanResponses = new ArrayList<>();
480+
481+
if (codegenResponse.getContent() != null && codegenResponse.getContent().get("application/json") != null &&
482+
codegenResponse.getContent().get("application/json").getExamples() != null) {
483+
484+
var examples = codegenResponse.getContent().get("application/json").getExamples();
485+
for (Map.Entry<String, Example> entry : examples.entrySet()) {
486+
String key = entry.getKey();
487+
String ref = entry.getValue().get$ref();
488+
489+
String response;
490+
if (ref != null) {
491+
// get example by $ref
492+
Example example = this.openAPI.getComponents().getExamples().get(extractExampleByName(ref));
493+
response = getJsonFromExample(example);
494+
} else {
495+
// get inline example
496+
response = getJsonFromExample(entry.getValue());
497+
}
498+
postmanResponses.add(new PostmanResponse(key, codegenResponse, message, response));
499+
}
500+
501+
} else if (codegenResponse.getContent() != null) {
502+
// TODO : Implement
503+
}
504+
505+
return postmanResponses;
506+
}
507+
508+
457509
/**
458510
* Returns human-friendly help for the generator. Provide the consumer with help
459511
* tips, parameters here
@@ -836,17 +888,65 @@ public String getPostmanType(CodegenProperty codegenProperty) {
836888
@Setter
837889
public class PostmanRequestItem {
838890

891+
private String id;
839892
private String name;
840893
private String body;
894+
private List<PostmanResponse> responses;
895+
896+
private PostmanRequestItem originalRequest;
841897

842898
public PostmanRequestItem() {
843899
}
844900

901+
public PostmanRequestItem(String id, String name, String body) {
902+
this.id = id;
903+
this.name = name;
904+
this.body = body;
905+
}
906+
845907
public PostmanRequestItem(String name, String body) {
846908
this.name = name;
847909
this.body = body;
848910
}
849911

912+
public void addResponses(List<PostmanResponse> responses) {
913+
if(this.responses == null) { this.responses = new ArrayList<>(); }
914+
915+
this.responses.addAll(responses);
916+
}
917+
918+
}
919+
920+
@Getter
921+
@Setter
922+
public class PostmanResponse {
923+
924+
private String id;
925+
private String code;
926+
private String status;
927+
private String name;
928+
private String body;
929+
private PostmanRequestItem originalRequest;
930+
931+
public PostmanResponse(String id, CodegenResponse response, String name, String body) {
932+
this.id = id;
933+
this.code = response.code;
934+
this.status = PostmanCollectionCodegen.this.getStatus(response);
935+
this.name = name;
936+
this.body = body;
937+
this.originalRequest = null; // Setting this here explicitly for clarity
938+
}
939+
940+
941+
public PostmanRequestItem getOriginalRequest() {
942+
return originalRequest;
943+
}
944+
945+
public void setOriginalRequest(PostmanRequestItem originalRequest) {
946+
this.originalRequest = originalRequest;
947+
}
948+
949+
850950
}
851951

852952
@Getter

modules/openapi-generator/src/main/resources/postman-collection/item.mustache

Lines changed: 17 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,59 +5,23 @@
55
{{#vendorExtensions.postmanRequests}}
66
{
77
"name": "{{{name}}}",
8-
"request": {
9-
"method": "{{httpMethod}}",
10-
"header": [
11-
{{#headerParams}}
12-
{
13-
"key": "{{baseName}}",
14-
"value": "{{schema.defaultValue}}",
15-
"description": "{{{description}}}",
16-
"disabled": {{#schema.defaultValue}}false{{/schema.defaultValue}}{{^schema.defaultValue}}true{{/schema.defaultValue}}
17-
}{{^-last}},{{/-last}}
18-
{{/headerParams}}
19-
],
20-
"body": {
21-
"mode": "raw",
22-
"raw": "{{{body}}}",
23-
"options": {
24-
"raw": {
25-
"language": "json"
26-
}
27-
}
28-
},
29-
"url": {
30-
"raw": "{{=<% %>=}}{{baseUrl}}<%={{ }}=%>{{{path}}}",
31-
"host": [
32-
"{{=<% %>=}}{{baseUrl}}<%={{ }}=%>"
33-
],
34-
"path": [
35-
{{#vendorExtensions.pathSegments}}
36-
"{{.}}"{{^-last}},{{/-last}}
37-
{{/vendorExtensions.pathSegments}}
38-
],
39-
"variable": [
40-
{{#pathParams}}
41-
{
42-
"key": "{{paramName}}",
43-
"value": "{{defaultValue}}",
44-
"description": "{{{description}}}"
45-
}{{^-last}},{{/-last}}
46-
{{/pathParams}}
47-
],
48-
"query": [
49-
{{#queryParams}}
50-
{
51-
"key": "{{paramName}}",
52-
"value": "{{example}}",
53-
"description": "{{{description}}}",
54-
"disabled": {{#required}}false{{/required}}{{^required}}true{{/required}}
55-
}{{^-last}},{{/-last}}
56-
{{/queryParams}}
57-
]
58-
},
59-
"description": "{{{notes}}}"
60-
}
8+
"request": {{>request}}
9+
,"response": [
10+
{{#responses}}
11+
{"name": "{{name}}",
12+
"code": {{code}},
13+
"status": "{{status}}",
14+
"header": [{
15+
"key": "Content-Type",
16+
"value": "application/json"}
17+
],
18+
"_postman_previewlanguage": "json",
19+
"cookie": [],
20+
"body" : "{{{body}}}",
21+
"originalRequest": {{#originalRequest}}{{>request}}{{/originalRequest}}
22+
}{{^-last}},{{/-last}}
23+
{{/responses}}
24+
]
6125
}{{^-last}},{{/-last}}
6226
{{/vendorExtensions.postmanRequests}}
6327
]
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"method": "{{httpMethod}}",
3+
"header": [
4+
{{#headerParams}}
5+
{
6+
"key": "{{baseName}}",
7+
"value": "{{schema.defaultValue}}",
8+
"description": "{{{description}}}",
9+
"disabled": {{#schema.defaultValue}}false{{/schema.defaultValue}}{{^schema.defaultValue}}true{{/schema.defaultValue}}
10+
}{{^-last}},{{/-last}}
11+
{{/headerParams}}
12+
],
13+
"body": {
14+
"mode": "raw",
15+
"raw": "{{{body}}}",
16+
"options": {
17+
"raw": {
18+
"language": "json"
19+
}
20+
}
21+
},
22+
"url": {
23+
"raw": "{{=<% %>=}}{{baseUrl}}<%={{ }}=%>{{path}}",
24+
"host": [
25+
"{{=<% %>=}}{{baseUrl}}<%={{ }}=%>"
26+
],
27+
"path": [
28+
{{#vendorExtensions.pathSegments}}
29+
"{{.}}"{{^-last}},{{/-last}}
30+
{{/vendorExtensions.pathSegments}}
31+
],
32+
"variable": [
33+
{{#pathParams}}
34+
{
35+
"key": "{{paramName}}",
36+
"value": "{{defaultValue}}",
37+
"description": "{{{description}}}"
38+
}{{^-last}},{{/-last}}
39+
{{/pathParams}}
40+
],
41+
"query": [
42+
{{#queryParams}}
43+
{
44+
"key": "{{paramName}}",
45+
"value": "{{example}}",
46+
"description": "{{{description}}}",
47+
"disabled": {{#required}}false{{/required}}{{^required}}true{{/required}}
48+
}{{^-last}},{{/-last}}
49+
{{/queryParams}}
50+
]
51+
},
52+
"description": "{{{notes}}}"
53+
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/postman/PostmanCollectionCodegenTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,4 +740,50 @@ public void testAddToMapUsingDefaultTag() {
740740
assertEquals(true, postmanV2Generator.codegenOperationsByTag.containsKey("default"));
741741
}
742742

743+
@Test
744+
public void testResponses() throws IOException {
745+
746+
File output = Files.createTempDirectory("postmantest_").toFile();
747+
output.deleteOnExit();
748+
749+
final CodegenConfigurator configurator = new CodegenConfigurator()
750+
.setGeneratorName("postman-collection")
751+
.setInputSpec("src/test/resources/3_0/postman-collection/SampleProject.yaml")
752+
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
753+
754+
DefaultGenerator generator = new DefaultGenerator();
755+
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
756+
757+
System.out.println(files);
758+
//files.forEach(File::deleteOnExit);
759+
760+
Path path = Paths.get(output + "/postman.json");
761+
TestUtils.assertFileExists(path);
762+
763+
TestUtils.assertFileContains(path, "\"response\": [\n" +
764+
" {\"name\": \"User Updated\",\n" +
765+
" \"code\": 200,\n" +
766+
" \"status\": \"OK\",\n" +
767+
" \"header\": [{\n" +
768+
" \"key\": \"Content-Type\",\n" +
769+
" \"value\": \"application/json\"}\n" +
770+
" ],\n" +
771+
" \"_postman_previewlanguage\": \"json\",\n" +
772+
" \"cookie\": [],\n" +
773+
" \"body\" : \"{\\n \\\"id\\\" : 1,\\n");
774+
775+
TestUtils.assertFileContains(path, "\"response\": [\n" +
776+
" {\"name\": \"User Updated\",\n" +
777+
" \"code\": 200,\n" +
778+
" \"status\": \"OK\",\n" +
779+
" \"header\": [{\n" +
780+
" \"key\": \"Content-Type\",\n" +
781+
" \"value\": \"application/json\"}\n" +
782+
" ],\n" +
783+
" \"_postman_previewlanguage\": \"json\",\n" +
784+
" \"cookie\": [],\n" +
785+
" \"body\" : \"{\\n \\\"id\\\" : 2,\\n");
786+
787+
}
788+
743789
}

0 commit comments

Comments
 (0)