Skip to content

Commit 8ca1dfa

Browse files
committed
Improve handling of requests with both parameters and content
Previously, if a MockMvc request was made with parameters and body content, the parameters were omitted from the resulting curl, HTTPie and HTTP request snippets. This commit updates the affected snippets to ensure that the parameters are included. The user-provided content is interpreted as indicating that the parameters should be sent in the query string rather than as form-encoded content. Closes gh-239
1 parent 3751939 commit 8ca1dfa

File tree

7 files changed

+144
-7
lines changed

7 files changed

+144
-7
lines changed

spring-restdocs-core/src/main/java/org/springframework/restdocs/cli/CurlRequestSnippet.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,16 @@ protected Map<String, Object> createModel(Operation operation) {
6969
}
7070

7171
private String getUrl(Operation operation) {
72-
return String.format("'%s'", operation.getRequest().getUri());
72+
OperationRequest request = operation.getRequest();
73+
if (!request.getParameters().isEmpty() && includeParametersInUri(request)) {
74+
return String.format("'%s?%s'", request.getUri(),
75+
request.getParameters().toQueryString());
76+
}
77+
return String.format("'%s'", request.getUri());
78+
}
79+
80+
private boolean includeParametersInUri(OperationRequest request) {
81+
return request.getMethod() == HttpMethod.GET || request.getContent().length > 0;
7382
}
7483

7584
private String getOptions(Operation operation) {

spring-restdocs-core/src/main/java/org/springframework/restdocs/cli/HttpieRequestSnippet.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Map.Entry;
2525

2626
import org.springframework.http.HttpHeaders;
27+
import org.springframework.http.HttpMethod;
2728
import org.springframework.http.MediaType;
2829
import org.springframework.restdocs.operation.Operation;
2930
import org.springframework.restdocs.operation.OperationRequest;
@@ -89,7 +90,11 @@ private String getOptions(CliOperationRequest request) {
8990
return options.toString();
9091
}
9192

92-
private String getUrl(OperationRequest request) {
93+
private String getUrl(CliOperationRequest request) {
94+
if (!request.getUniqueParameters().isEmpty() && includeParametersInUri(request)) {
95+
return String.format("'%s?%s'", request.getUri(),
96+
request.getParameters().toQueryString());
97+
}
9398
return String.format("'%s'", request.getUri());
9499
}
95100

@@ -103,11 +108,16 @@ private String getRequestItems(CliOperationRequest request) {
103108
}
104109

105110
private void writeOptions(CliOperationRequest request, PrintWriter writer) {
106-
if (!request.getParts().isEmpty() || !request.getUniqueParameters().isEmpty()) {
111+
if (!request.getParts().isEmpty() || (!request.getUniqueParameters().isEmpty()
112+
&& !includeParametersInUri(request))) {
107113
writer.print("--form ");
108114
}
109115
}
110116

117+
private boolean includeParametersInUri(CliOperationRequest request) {
118+
return request.getMethod() == HttpMethod.GET || request.getContent().length > 0;
119+
}
120+
111121
private void writeUserOptionIfNecessary(CliOperationRequest request,
112122
PrintWriter writer) {
113123
String credentials = request.getBasicAuthCredentials();

spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpRequestSnippet.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,33 @@ protected HttpRequestSnippet(Map<String, Object> attributes) {
6666
protected Map<String, Object> createModel(Operation operation) {
6767
Map<String, Object> model = new HashMap<>();
6868
model.put("method", operation.getRequest().getMethod());
69-
model.put("path", operation.getRequest().getUri().getRawPath()
70-
+ (StringUtils.hasText(operation.getRequest().getUri().getRawQuery())
71-
? "?" + operation.getRequest().getUri().getRawQuery() : ""));
69+
model.put("path", getPath(operation.getRequest()));
7270
model.put("headers", getHeaders(operation.getRequest()));
7371
model.put("requestBody", getRequestBody(operation.getRequest()));
7472
return model;
7573
}
7674

75+
private String getPath(OperationRequest request) {
76+
String path = request.getUri().getRawPath();
77+
String queryString = request.getUri().getRawQuery();
78+
if (!request.getParameters().isEmpty() && includeParametersInUri(request)) {
79+
if (StringUtils.hasText(queryString)) {
80+
queryString = queryString + "&" + request.getParameters().toQueryString();
81+
}
82+
else {
83+
queryString = request.getParameters().toQueryString();
84+
}
85+
}
86+
if (StringUtils.hasText(queryString)) {
87+
path = path + "?" + queryString;
88+
}
89+
return path;
90+
}
91+
92+
private boolean includeParametersInUri(OperationRequest request) {
93+
return request.getMethod() == HttpMethod.GET || request.getContent().length > 0;
94+
}
95+
7796
private List<Map<String, String>> getHeaders(OperationRequest request) {
7897
List<Map<String, String>> headers = new ArrayList<>();
7998

@@ -172,7 +191,8 @@ private void writeMultipartEnd(PrintWriter writer) {
172191

173192
private boolean requiresFormEncodingContentTypeHeader(OperationRequest request) {
174193
return request.getHeaders().get(HttpHeaders.CONTENT_TYPE) == null
175-
&& isPutOrPost(request) && !request.getParameters().isEmpty();
194+
&& isPutOrPost(request) && (!request.getParameters().isEmpty()
195+
&& !includeParametersInUri(request));
176196
}
177197

178198
private Map<String, String> header(String name, String value) {

spring-restdocs-core/src/test/java/org/springframework/restdocs/cli/CurlRequestSnippetTests.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ public void getRequest() throws IOException {
6161
operationBuilder("get-request").request("http://localhost/foo").build());
6262
}
6363

64+
@Test
65+
public void getRequestWithParameter() throws IOException {
66+
this.snippet.expectCurlRequest("get-request").withContents(
67+
codeBlock("bash").content("$ curl 'http://localhost/foo?a=alpha' -i"));
68+
new CurlRequestSnippet().document(operationBuilder("get-request")
69+
.request("http://localhost/foo").param("a", "alpha").build());
70+
}
71+
6472
@Test
6573
public void nonGetRequest() throws IOException {
6674
this.snippet.expectCurlRequest("non-get-request").withContents(
@@ -344,4 +352,17 @@ public void customHostHeaderIsIncluded() throws IOException {
344352
.header("a", "alpha").build());
345353
}
346354

355+
@Test
356+
public void postWithContentAndParameters() throws IOException {
357+
this.snippet.expectCurlRequest("post-with-content-and-parameters")
358+
.withContents(codeBlock("bash")
359+
.content("$ curl 'http://localhost/foo?a=alpha&b=bravo' -i "
360+
+ "-X POST -d 'Some content'"));
361+
new CurlRequestSnippet()
362+
.document(operationBuilder("post-with-content-and-parameters")
363+
.request("http://localhost/foo").param("a", "alpha")
364+
.method("POST").param("b", "bravo").content("Some content")
365+
.build());
366+
}
367+
347368
}

spring-restdocs-core/src/test/java/org/springframework/restdocs/cli/HttpieRequestSnippetTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ public void getRequest() throws IOException {
6262
operationBuilder("get-request").request("http://localhost/foo").build());
6363
}
6464

65+
@Test
66+
public void getRequestWithParameter() throws IOException {
67+
this.snippet.expectHttpieRequest("get-request-with-parameter").withContents(
68+
codeBlock("bash").content("$ http GET 'http://localhost/foo?a=alpha'"));
69+
new HttpieRequestSnippet().document(operationBuilder("get-request-with-parameter")
70+
.request("http://localhost/foo").param("a", "alpha").build());
71+
}
72+
6573
@Test
6674
public void nonGetRequest() throws IOException {
6775
this.snippet.expectHttpieRequest("non-get-request").withContents(
@@ -346,4 +354,16 @@ public void customHostHeaderIsIncluded() throws IOException {
346354
.header("a", "alpha").build());
347355
}
348356

357+
@Test
358+
public void postWithContentAndParameters() throws IOException {
359+
this.snippet.expectHttpieRequest("post-with-content-and-parameters").withContents(
360+
codeBlock("bash").content("$ echo 'Some content' | http POST "
361+
+ "'http://localhost/foo?a=alpha&b=bravo'"));
362+
new HttpieRequestSnippet()
363+
.document(operationBuilder("post-with-content-and-parameters")
364+
.request("http://localhost/foo").method("POST")
365+
.param("a", "alpha").param("b", "bravo").content("Some content")
366+
.build());
367+
}
368+
349369
}

spring-restdocs-core/src/test/java/org/springframework/restdocs/http/HttpRequestSnippetTests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ public void getRequest() throws IOException {
5959
.request("http://localhost/foo").header("Alpha", "a").build());
6060
}
6161

62+
@Test
63+
public void getRequestWithParameters() throws IOException {
64+
this.snippet.expectHttpRequest("get-request-with-parameters")
65+
.withContents(httpRequest(RequestMethod.GET, "/foo?b=bravo")
66+
.header("Alpha", "a").header(HttpHeaders.HOST, "localhost"));
67+
68+
new HttpRequestSnippet().document(operationBuilder("get-request-with-parameters")
69+
.request("http://localhost/foo").header("Alpha", "a").param("b", "bravo")
70+
.build());
71+
}
72+
6273
@Test
6374
public void getRequestWithPort() throws IOException {
6475
this.snippet.expectHttpRequest("get-request")
@@ -103,6 +114,20 @@ public void postRequestWithContent() throws IOException {
103114
.request("http://localhost/foo").method("POST").content(content).build());
104115
}
105116

117+
@Test
118+
public void postRequestWithContentAndParameters() throws IOException {
119+
String content = "Hello, world";
120+
this.snippet.expectHttpRequest("post-request-with-content-and-parameters")
121+
.withContents(httpRequest(RequestMethod.POST, "/foo?a=alpha")
122+
.header(HttpHeaders.HOST, "localhost").content(content).header(
123+
HttpHeaders.CONTENT_LENGTH, content.getBytes().length));
124+
125+
new HttpRequestSnippet()
126+
.document(operationBuilder("post-request-with-content-and-parameters")
127+
.request("http://localhost/foo").method("POST")
128+
.param("a", "alpha").content(content).build());
129+
}
130+
106131
@Test
107132
public void postRequestWithCharset() throws IOException {
108133
String japaneseContent = "\u30b3\u30f3\u30c6\u30f3\u30c4";

spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationIntegrationTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,22 @@ public void curlSnippetWithQueryStringOnPost() throws Exception {
175175
+ "-H 'Accept: application/json' -d 'a=alpha'"))));
176176
}
177177

178+
@Test
179+
public void curlSnippetWithContentAndParametersOnPost() throws Exception {
180+
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
181+
.apply(documentationConfiguration(this.restDocumentation)).build();
182+
mockMvc.perform(post("/").param("a", "alpha").accept(MediaType.APPLICATION_JSON)
183+
.content("some content")).andExpect(status().isOk())
184+
.andDo(document("curl-snippet-with-content-and-parameters"));
185+
assertThat(
186+
new File(
187+
"build/generated-snippets/curl-snippet-with-content-and-parameters/curl-request.adoc"),
188+
is(snippet(asciidoctor())
189+
.withContents(codeBlock(asciidoctor(), "bash").content("$ curl "
190+
+ "'http://localhost:8080/?a=alpha' -i -X POST "
191+
+ "-H 'Accept: application/json' -d 'some content'"))));
192+
}
193+
178194
@Test
179195
public void httpieSnippetWithContent() throws Exception {
180196
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
@@ -207,6 +223,22 @@ public void httpieSnippetWithQueryStringOnPost() throws Exception {
207223
+ "'Accept:application/json' 'a=alpha'"))));
208224
}
209225

226+
@Test
227+
public void httpieSnippetWithContentAndParametersOnPost() throws Exception {
228+
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
229+
.apply(documentationConfiguration(this.restDocumentation)).build();
230+
mockMvc.perform(post("/").param("a", "alpha").content("some content")
231+
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
232+
.andDo(document("httpie-snippet-post-with-content-and-parameters"));
233+
assertThat(
234+
new File(
235+
"build/generated-snippets/httpie-snippet-post-with-content-and-parameters/httpie-request.adoc"),
236+
is(snippet(asciidoctor()).withContents(codeBlock(asciidoctor(), "bash")
237+
.content("$ echo " + "'some content' | http POST "
238+
+ "'http://localhost:8080/?a=alpha' "
239+
+ "'Accept:application/json'"))));
240+
}
241+
210242
@Test
211243
public void linksSnippet() throws Exception {
212244
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)

0 commit comments

Comments
 (0)