Repository: springdoc/springdoc-openapi
Pull request #1814 (2022-08-24 21:45:12)

Allow requestBody creation for GET on openapi resource endpoint
Related to #1813 




Patch:
diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/AbstractRequestService.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/AbstractRequestService.java
index 5df680f5a..fa4fe0783 100644
--- a/springdoc-openapi-common/src/main/java/org/springdoc/core/AbstractRequestService.java
+++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/AbstractRequestService.java
@@ -64,6 +64,7 @@ import io.swagger.v3.oas.models.parameters.RequestBody;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
+import org.springdoc.core.SpringDocConfigProperties.ApiDocs.OpenApiVersion;
 import org.springdoc.core.customizers.ParameterCustomizer;
 import org.springdoc.core.providers.JavadocProvider;
 
@@ -291,7 +292,8 @@ public abstract class AbstractRequestService {
 			}
 
 			if (!isParamToIgnore(methodParameter)) {
-				parameter = buildParams(parameterInfo, components, requestMethod, methodAttributes.getJsonViewAnnotation());
+				parameter = buildParams(parameterInfo, components, requestMethod, methodAttributes.getJsonViewAnnotation(),
+																openAPI.getOpenapi());
 				// Merge with the operation parameters
 				parameter = GenericParameterService.mergeParameter(operationParameters, parameter);
 				List<Annotation> parameterAnnotations = Arrays.asList(methodParameter.getParameterAnnotations());
@@ -305,7 +307,7 @@ public abstract class AbstractRequestService {
 					}
 					applyBeanValidatorAnnotations(parameter, parameterAnnotations);
 				}
-				else if (!RequestMethod.GET.equals(requestMethod)) {
+				else if (!RequestMethod.GET.equals(requestMethod) || OpenApiVersion.OPENAPI_3_1.getVersion().equals(openAPI.getOpenapi())) {
 					if (operation.getRequestBody() != null)
 						requestBodyInfo.setRequestBody(operation.getRequestBody());
 					requestBodyService.calculateRequestBodyInfo(components, methodAttributes,
@@ -488,10 +490,11 @@ public abstract class AbstractRequestService {
 	 * @param components the components
 	 * @param requestMethod the request method
 	 * @param jsonView the json view
+	 * @param openApiVersion the open api version
 	 * @return the parameter
 	 */
 	public Parameter buildParams(ParameterInfo parameterInfo, Components components,
-			RequestMethod requestMethod, JsonView jsonView) {
+			RequestMethod requestMethod, JsonView jsonView, String openApiVersion) {
 		MethodParameter methodParameter = parameterInfo.getMethodParameter();
 		if (parameterInfo.getParamType() != null) {
 			if (!ValueConstants.DEFAULT_NONE.equals(parameterInfo.getDefaultValue()))
@@ -501,7 +504,7 @@ public abstract class AbstractRequestService {
 			return this.buildParam(parameterInfo, components, jsonView);
 		}
 		// By default
-		if (!isRequestBodyParam(requestMethod, parameterInfo)) {
+		if (!isRequestBodyParam(requestMethod, parameterInfo, openApiVersion)) {
 			parameterInfo.setRequired(!((DelegatingMethodParameter) methodParameter).isNotRequired() && !methodParameter.isOptional());
 			parameterInfo.setParamType(QUERY_PARAM);
 			parameterInfo.setDefaultValue(null);
@@ -715,13 +718,15 @@ public abstract class AbstractRequestService {
 	 *
 	 * @param requestMethod the request method
 	 * @param parameterInfo the parameter info
+	 * @param openApiVersion the open api version
 	 * @return the boolean
 	 */
-	private boolean isRequestBodyParam(RequestMethod requestMethod, ParameterInfo parameterInfo) {
+	private boolean isRequestBodyParam(RequestMethod requestMethod, ParameterInfo parameterInfo, String openApiVersion) {
 		MethodParameter methodParameter = parameterInfo.getMethodParameter();
 		DelegatingMethodParameter delegatingMethodParameter = (DelegatingMethodParameter) methodParameter;
+		Boolean isBodyAllowed = !RequestMethod.GET.equals(requestMethod) || OpenApiVersion.OPENAPI_3_1.getVersion().equals(openApiVersion);
 
-		return (!RequestMethod.GET.equals(requestMethod) && (parameterInfo.getParameterModel() == null || parameterInfo.getParameterModel().getIn() == null) && !delegatingMethodParameter.isParameterObject())
+		return (isBodyAllowed && (parameterInfo.getParameterModel() == null || parameterInfo.getParameterModel().getIn() == null) && !delegatingMethodParameter.isParameterObject())
 				&&
 				((methodParameter.getParameterAnnotation(io.swagger.v3.oas.annotations.parameters.RequestBody.class) != null
 						|| methodParameter.getParameterAnnotation(org.springframework.web.bind.annotation.RequestBody.class) != null
diff --git a/springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/core/DataRestRequestService.java b/springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/core/DataRestRequestService.java
index 361085f1e..23cf47aa4 100644
--- a/springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/core/DataRestRequestService.java
+++ b/springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/core/DataRestRequestService.java
@@ -173,7 +173,8 @@ public class DataRestRequestService {
 					parameterInfo.setParameterModel(parameter);
 				}
 				if (!ArrayUtils.isEmpty(methodParameter.getParameterAnnotations()))
-					parameter = requestBuilder.buildParams(parameterInfo, openAPI.getComponents(), requestMethod, null);
+					parameter = requestBuilder.buildParams(parameterInfo, openAPI.getComponents(), requestMethod, null,
+																								 openAPI.getOpenapi());
 
 				addParameters(openAPI, requestMethod, methodAttributes, operation, methodParameter, parameterInfo, parameter);
 			}


Test patch:
diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v31/app6/DummyData.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v31/app6/DummyData.java
new file mode 100644
index 000000000..4cbfaba86
--- /dev/null
+++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v31/app6/DummyData.java
@@ -0,0 +1,58 @@
+/*
+ *
+ *  *
+ *  *  *
+ *  *  *  * Copyright 2019-2022 the original author or authors.
+ *  *  *  *
+ *  *  *  * Licensed under the Apache License, Version 2.0 (the "License");
+ *  *  *  * you may not use this file except in compliance with the License.
+ *  *  *  * You may obtain a copy of the License at
+ *  *  *  *
+ *  *  *  *      https://www.apache.org/licenses/LICENSE-2.0
+ *  *  *  *
+ *  *  *  * Unless required by applicable law or agreed to in writing, software
+ *  *  *  * distributed under the License is distributed on an "AS IS" BASIS,
+ *  *  *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  *  *  * See the License for the specific language governing permissions and
+ *  *  *  * limitations under the License.
+ *  *  *
+ *  *
+ *
+ */
+
+package test.org.springdoc.api.v31.app6;
+
+import java.time.Instant;
+
+public class DummyData {
+
+	String trackerId;
+
+	Instant timestamp;
+
+	Double value;
+
+	public String getTrackerId() {
+		return trackerId;
+	}
+
+	public void setTrackerId(String trackerId) {
+		this.trackerId = trackerId;
+	}
+
+	public Instant getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(Instant timestamp) {
+		this.timestamp = timestamp;
+	}
+
+	public Double getValue() {
+		return value;
+	}
+
+	public void setValue(Double value) {
+		this.value = value;
+	}
+}
diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v31/app6/GetBodyController.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v31/app6/GetBodyController.java
new file mode 100644
index 000000000..4001a35b2
--- /dev/null
+++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v31/app6/GetBodyController.java
@@ -0,0 +1,39 @@
+/*
+ *
+ *  *
+ *  *  *
+ *  *  *  * Copyright 2019-2022 the original author or authors.
+ *  *  *  *
+ *  *  *  * Licensed under the Apache License, Version 2.0 (the "License");
+ *  *  *  * you may not use this file except in compliance with the License.
+ *  *  *  * You may obtain a copy of the License at
+ *  *  *  *
+ *  *  *  *      https://www.apache.org/licenses/LICENSE-2.0
+ *  *  *  *
+ *  *  *  * Unless required by applicable law or agreed to in writing, software
+ *  *  *  * distributed under the License is distributed on an "AS IS" BASIS,
+ *  *  *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  *  *  * See the License for the specific language governing permissions and
+ *  *  *  * limitations under the License.
+ *  *  *
+ *  *
+ *
+ */
+
+package test.org.springdoc.api.v31.app6;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import test.org.springdoc.api.v31.app4.TrackerData;
+
+@RestController
+public class GetBodyController {
+
+	@GetMapping(value = "/get/body")
+  DummyData getBody(@RequestBody DummyData dummyData) {
+		return dummyData;
+
+	}
+
+}
diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v31/app6/SpringDocApp6Test.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v31/app6/SpringDocApp6Test.java
new file mode 100644
index 000000000..0c979a7eb
--- /dev/null
+++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/v31/app6/SpringDocApp6Test.java
@@ -0,0 +1,34 @@
+/*
+ *
+ *  *
+ *  *  *
+ *  *  *  * Copyright 2019-2022 the original author or authors.
+ *  *  *  *
+ *  *  *  * Licensed under the Apache License, Version 2.0 (the "License");
+ *  *  *  * you may not use this file except in compliance with the License.
+ *  *  *  * You may obtain a copy of the License at
+ *  *  *  *
+ *  *  *  *      https://www.apache.org/licenses/LICENSE-2.0
+ *  *  *  *
+ *  *  *  * Unless required by applicable law or agreed to in writing, software
+ *  *  *  * distributed under the License is distributed on an "AS IS" BASIS,
+ *  *  *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  *  *  * See the License for the specific language governing permissions and
+ *  *  *  * limitations under the License.
+ *  *  *
+ *  *
+ *
+ */
+
+package test.org.springdoc.api.v31.app6;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import test.org.springdoc.api.v31.AbstractSpringDocV31Test;
+
+public class SpringDocApp6Test extends AbstractSpringDocV31Test {
+
+  @SpringBootApplication
+  static class SpringDocTestApp {
+
+  }
+}
diff --git a/springdoc-openapi-webmvc-core/src/test/resources/results/3.1.0/app6.json b/springdoc-openapi-webmvc-core/src/test/resources/results/3.1.0/app6.json
new file mode 100644
index 000000000..6c8b64925
--- /dev/null
+++ b/springdoc-openapi-webmvc-core/src/test/resources/results/3.1.0/app6.json
@@ -0,0 +1,64 @@
+{
+  "openapi": "3.1.0",
+  "info": {
+    "title": "OpenAPI definition",
+    "version": "v0"
+  },
+  "servers": [
+    {
+      "url": "http://localhost",
+      "description": "Generated server url"
+    }
+  ],
+  "paths": {
+    "/get/body": {
+      "get": {
+        "tags": [
+          "get-body-controller"
+        ],
+        "operationId": "getBody",
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/DummyData"
+              }
+            }
+          },
+          "required": true
+        },
+        "responses": {
+          "200": {
+            "description": "OK",
+            "content": {
+              "*/*": {
+                "schema": {
+                  "$ref": "#/components/schemas/DummyData"
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "DummyData": {
+        "properties": {
+          "trackerId": {
+            "type": "string"
+          },
+          "timestamp": {
+            "type": "string",
+            "format": "date-time"
+          },
+          "value": {
+            "type": "number",
+            "format": "double"
+          }
+        }
+      }
+    }
+  }
+}