RequestBodyTest.java
package io.swagger.v3.jaxrs2.annotations.requests;
import io.swagger.v3.jaxrs2.Reader;
import io.swagger.v3.jaxrs2.annotations.AbstractAnnotationTest;
import io.swagger.v3.jaxrs2.it.resources.MultiPartFileResource;
import io.swagger.v3.jaxrs2.it.resources.OctetStreamResource;
import io.swagger.v3.jaxrs2.it.resources.UrlEncodedResource;
import io.swagger.v3.jaxrs2.resources.model.Pet;
import io.swagger.v3.jaxrs2.resources.model.User;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.PathItem;
import org.testng.annotations.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PATCH;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.io.IOException;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
public class RequestBodyTest extends AbstractAnnotationTest {
private static final String REQUEST_BODY_IN_METHOD = "RequestBody in Method";
private static final String REQUEST_BODY_IN_PARAMETER = "Request Body in Param";
private static final String NO_IN_PARAMETER = "Parameter with no IN";
private static final String REQUEST_BODY_IN_ANNOTATION = "RequestBody in Annotation";
private static final String USER_PATH = "/user";
@Test(description = "Returns a request with one RequestBody and multiple parameters")
public void oneRequestBodyMultipleParameters() throws IOException {
String expectedYAML = "openapi: 3.0.1\n" +
"paths:\n" +
" /user:\n" +
" put:\n" +
" summary: Modify user\n" +
" description: Modifying user.\n" +
" operationId: methodWithRequestBodyWithoutAnnotation\n" +
" requestBody:\n" +
" content:\n" +
" '*/*':\n" +
" schema:\n" +
" $ref: \"#/components/schemas/User\"\n" +
" responses:\n" +
" default:\n" +
" description: default response\n" +
" content:\n" +
" '*/*': {}\n" +
" post:\n" +
" summary: Create user\n" +
" description: This can only be done by the logged in user.\n" +
" operationId: methodWithRequestBodyAndTwoParameters\n" +
" parameters:\n" +
" - name: name\n" +
" in: query\n" +
" schema:\n" +
" type: string\n" +
" - name: code\n" +
" in: query\n" +
" schema:\n" +
" type: string\n" +
" requestBody:\n" +
" description: Created user object\n" +
" content:\n" +
" '*/*':\n" +
" schema:\n" +
" $ref: \"#/components/schemas/User\"\n" +
" required: true\n" +
" responses:\n" +
" default:\n" +
" description: default response\n" +
" content:\n" +
" '*/*': {}\n" +
" delete:\n" +
" summary: Delete user\n" +
" description: This can only be done by the logged in user.\n" +
" operationId: methodWithoutRequestBodyAndTwoParameters\n" +
" parameters:\n" +
" - name: name\n" +
" in: query\n" +
" schema:\n" +
" type: string\n" +
" - name: code\n" +
" in: query\n" +
" schema:\n" +
" type: string\n" +
" responses:\n" +
" default:\n" +
" description: default response\n" +
" content:\n" +
" '*/*': {}\n" +
" /pet:\n" +
" put:\n" +
" summary: Modify pet\n" +
" description: Modifying pet.\n" +
" operationId: methodWithRequestBodyWithoutAnnotationAndTwoConsumes\n" +
" requestBody:\n" +
" content:\n" +
" application/json:\n" +
" schema:\n" +
" $ref: \"#/components/schemas/User\"\n" +
" application/xml:\n" +
" schema:\n" +
" $ref: \"#/components/schemas/User\"\n" +
" responses:\n" +
" default:\n" +
" description: default response\n" +
" content:\n" +
" '*/*': {}\n" +
" post:\n" +
" summary: Create pet\n" +
" description: Creating pet.\n" +
" operationId: methodWithTwoRequestBodyWithoutAnnotationAndTwoConsumes\n" +
" requestBody:\n" +
" content:\n" +
" application/json:\n" +
" schema:\n" +
" $ref: \"#/components/schemas/Pet\"\n" +
" application/xml:\n" +
" schema:\n" +
" $ref: \"#/components/schemas/Pet\"\n" +
" responses:\n" +
" default:\n" +
" description: default response\n" +
" content:\n" +
" '*/*': {}\n" +
" delete:\n" +
" summary: Delete pet\n" +
" description: Deleting pet.\n" +
" operationId: methodWithOneSimpleRequestBody\n" +
" requestBody:\n" +
" content:\n" +
" application/json:\n" +
" schema:\n" +
" type: integer\n" +
" format: int32\n" +
" application/xml:\n" +
" schema:\n" +
" type: integer\n" +
" format: int32\n" +
" responses:\n" +
" default:\n" +
" description: default response\n" +
" content:\n" +
" '*/*': {}\n" +
"components:\n" +
" schemas:\n" +
" User:\n" +
" type: object\n" +
" properties:\n" +
" id:\n" +
" type: integer\n" +
" format: int64\n" +
" username:\n" +
" type: string\n" +
" firstName:\n" +
" type: string\n" +
" lastName:\n" +
" type: string\n" +
" email:\n" +
" type: string\n" +
" password:\n" +
" type: string\n" +
" phone:\n" +
" type: string\n" +
" userStatus:\n" +
" type: integer\n" +
" description: User Status\n" +
" format: int32\n" +
" xml:\n" +
" name: User\n" +
" Category:\n" +
" type: object\n" +
" properties:\n" +
" id:\n" +
" type: integer\n" +
" format: int64\n" +
" name:\n" +
" type: string\n" +
" xml:\n" +
" name: Category\n" +
" Tag:\n" +
" type: object\n" +
" properties:\n" +
" id:\n" +
" type: integer\n" +
" format: int64\n" +
" name:\n" +
" type: string\n" +
" xml:\n" +
" name: Tag\n" +
" Pet:\n" +
" type: object\n" +
" properties:\n" +
" id:\n" +
" type: integer\n" +
" format: int64\n" +
" category:\n" +
" $ref: \"#/components/schemas/Category\"\n" +
" name:\n" +
" type: string\n" +
" photoUrls:\n" +
" type: array\n" +
" xml:\n" +
" wrapped: true\n" +
" items:\n" +
" type: string\n" +
" xml:\n" +
" name: photoUrl\n" +
" tags:\n" +
" type: array\n" +
" xml:\n" +
" wrapped: true\n" +
" items:\n" +
" $ref: \"#/components/schemas/Tag\"\n" +
" status:\n" +
" type: string\n" +
" description: pet status in the store\n" +
" enum:\n" +
" - available,pending,sold\n" +
" xml:\n" +
" name: Pet";
compareAsYaml(RequestBodyTest.UserResource.class, expectedYAML);
}
static class UserResource {
@POST
@Path("/user")
@Operation(summary = "Create user",
description = "This can only be done by the logged in user.")
public Response methodWithRequestBodyAndTwoParameters(
@RequestBody(description = "Created user object", required = true,
content = @Content(
schema = @Schema(implementation = User.class))) User user,
@QueryParam("name") String name, @QueryParam("code") String code) {
return Response.ok().entity("").build();
}
@PUT
@Path("/user")
@Operation(summary = "Modify user",
description = "Modifying user.")
public Response methodWithRequestBodyWithoutAnnotation(
User user) {
return Response.ok().entity("").build();
}
@DELETE
@Path("/user")
@Operation(summary = "Delete user",
description = "This can only be done by the logged in user.")
public Response methodWithoutRequestBodyAndTwoParameters(
@QueryParam("name") String name, @QueryParam("code") String code) {
return Response.ok().entity("").build();
}
@PUT
@Path("/pet")
@Operation(summary = "Modify pet",
description = "Modifying pet.")
@Consumes({"application/json", "application/xml"})
public Response methodWithRequestBodyWithoutAnnotationAndTwoConsumes(
User user) {
return Response.ok().entity("").build();
}
@POST
@Path("/pet")
@Operation(summary = "Create pet",
description = "Creating pet.")
@Consumes({"application/json", "application/xml"})
public Response methodWithTwoRequestBodyWithoutAnnotationAndTwoConsumes(
Pet pet, User user) {
return Response.ok().entity("").build();
}
@DELETE
@Path("/pet")
@Operation(summary = "Delete pet",
description = "Deleting pet.")
@Consumes({"application/json", "application/xml"})
public Response methodWithOneSimpleRequestBody(int id) {
return Response.ok().entity("").build();
}
}
@Test(description = "scan class with requesbody annotation")
public void testRequestBodyAnnotationPriority() {
Reader reader = new Reader(new OpenAPI());
OpenAPI openAPI = reader.read(RequestBodyResource.class);
PathItem userPathItem = openAPI.getPaths().get(USER_PATH);
io.swagger.v3.oas.models.parameters.RequestBody getRequestBody = userPathItem.getGet().getRequestBody();
assertNotNull(getRequestBody);
assertEquals(getRequestBody.getDescription(), REQUEST_BODY_IN_ANNOTATION);
io.swagger.v3.oas.models.parameters.RequestBody postRequestBody = userPathItem.getPost().getRequestBody();
assertNotNull(postRequestBody);
assertEquals(postRequestBody.getDescription(), REQUEST_BODY_IN_ANNOTATION);
io.swagger.v3.oas.models.parameters.RequestBody putRequestBody = userPathItem.getPut().getRequestBody();
assertNotNull(putRequestBody);
assertEquals(putRequestBody.getDescription(), REQUEST_BODY_IN_METHOD);
io.swagger.v3.oas.models.parameters.RequestBody deleteRequestBody = userPathItem.getDelete().getRequestBody();
assertNotNull(deleteRequestBody);
assertEquals(deleteRequestBody.getDescription(), REQUEST_BODY_IN_METHOD);
io.swagger.v3.oas.models.parameters.RequestBody patchRequestBody = userPathItem.getPatch().getRequestBody();
assertNotNull(patchRequestBody);
assertEquals(patchRequestBody.getDescription(), REQUEST_BODY_IN_METHOD);
userPathItem = openAPI.getPaths().get(USER_PATH + "/deleteUserMethod_Param_RequestBody");
deleteRequestBody = userPathItem.getDelete().getRequestBody();
assertNotNull(deleteRequestBody);
assertEquals(deleteRequestBody.getDescription(), REQUEST_BODY_IN_PARAMETER);
userPathItem = openAPI.getPaths().get(USER_PATH + "/deleteUserOperation_Method_Param_RequestBody");
deleteRequestBody = userPathItem.getDelete().getRequestBody();
assertNotNull(deleteRequestBody);
assertEquals(deleteRequestBody.getDescription(), REQUEST_BODY_IN_PARAMETER);
userPathItem = openAPI.getPaths().get(USER_PATH + "/deleteUserOperation_RequestBody");
deleteRequestBody = userPathItem.getDelete().getRequestBody();
assertNotNull(deleteRequestBody);
assertEquals(deleteRequestBody.getDescription(), REQUEST_BODY_IN_PARAMETER);
userPathItem = openAPI.getPaths().get(USER_PATH + "/deleteUserOperation_Method_Param");
deleteRequestBody = userPathItem.getDelete().getRequestBody();
assertNotNull(deleteRequestBody);
assertEquals(deleteRequestBody.getDescription(), REQUEST_BODY_IN_METHOD);
}
@Path("/user")
static class RequestBodyResource {
@GET
@Operation(requestBody = @RequestBody(description = "RequestBody in Annotation", required = true,
content = @Content(schema = @Schema(implementation = User.class))))
public User getUser() {
return new User();
}
@POST
@Operation(summary = "Create user",
description = "This can only be done by the logged in user.",
requestBody = @RequestBody(description = "RequestBody in Annotation", required = true,
content = @Content(schema = @Schema(implementation = User.class))))
public Response createUser(
@Parameter(description = "Parameter with no IN", required = true) User user) {
return Response.ok().entity("").build();
}
@PUT
@Operation(summary = "Update user",
description = "This can only be done by the logged in user.")
@RequestBody(description = "RequestBody in Method", required = true,
content = @Content(schema = @Schema(implementation = User.class)))
public Response updateUser() {
return Response.ok().entity("").build();
}
@DELETE
@Operation(summary = "Delete user",
description = "This can only be done by the logged in user.")
@RequestBody(description = "RequestBody in Method", required = true,
content = @Content(schema = @Schema(implementation = User.class)))
public Response deleteUser(@Parameter(description = "Parameter with no IN", required = true) User user) {
return Response.ok().entity("").build();
}
@DELETE
@Path("/deleteUserMethod_Param_RequestBody")
@Operation(summary = "Delete user",
description = "This can only be done by the logged in user.")
@RequestBody(description = "RequestBody in Method", required = true,
content = @Content(schema = @Schema(implementation = User.class)))
public Response deleteUserMethod_Param_RequestBody(
@Parameter(description = "Parameter with no IN", required = true)
@RequestBody(description = "Request Body in Param") User user) {
return Response.ok().entity("").build();
}
@DELETE
@Path("/deleteUserOperation_Method_Param_RequestBody")
@Operation(summary = "Delete user",
description = "This can only be done by the logged in user.",
requestBody = @RequestBody(description = "RequestBody in Annotation", required = true,
content = @Content(schema = @Schema(implementation = User.class))))
@RequestBody(description = "RequestBody in Method", required = true,
content = @Content(schema = @Schema(implementation = User.class)))
public Response deleteUserOperation_Method_Param_RequestBody(
@Parameter(description = "Parameter with no IN", required = true)
@RequestBody(description = "Request Body in Param") User user) {
return Response.ok().entity("").build();
}
@DELETE
@Path("/deleteUserOperation_Method_Param")
@Operation(summary = "Delete user",
description = "This can only be done by the logged in user.",
requestBody = @RequestBody(description = "RequestBody in Annotation", required = true,
content = @Content(schema = @Schema(implementation = User.class))))
@RequestBody(description = "RequestBody in Method", required = true,
content = @Content(schema = @Schema(implementation = User.class)))
public Response deleteUserOperation_Method_Param(
@Parameter(description = "Parameter with no IN", required = true) User user) {
return Response.ok().entity("").build();
}
@DELETE
@Path("/deleteUserOperation_RequestBody")
@Operation(summary = "Delete user",
description = "This can only be done by the logged in user.",
requestBody = @RequestBody(description = "RequestBody in Annotation", required = true,
content = @Content(schema = @Schema(implementation = User.class))))
public Response deleteUserOperation_RequestBody(
@RequestBody(description = "Request Body in Param") User user) {
return Response.ok().entity("").build();
}
@PATCH
@Operation(summary = "Modify user",
description = "This can only be done by the logged in user.",
requestBody = @RequestBody(description = "RequestBody in Annotation", required = true,
content = @Content(schema = @Schema(implementation = User.class))))
@RequestBody(description = "RequestBody in Method", required = true,
content = @Content(schema = @Schema(implementation = User.class)))
public Response modifyUser() {
return Response.ok().entity("").build();
}
}
@Test(description = "Test file upload")
public void testFileUploadOctetStream() throws IOException {
String expectedYAML = "openapi: 3.0.1\n" +
"paths:\n" +
" /files/attach:\n" +
" put:\n" +
" operationId: putFile\n" +
" requestBody:\n" +
" content:\n" +
" application/octet-stream:\n" +
" schema:\n" +
" type: string\n" +
" format: binary\n" +
" responses:\n" +
" default:\n" +
" description: default response\n" +
" content:\n" +
" application/json: {}";
compareAsYaml(OctetStreamResource.class, expectedYAML);
}
@Test(description = "Test urlencoded")
public void testUrlEncoded() throws IOException {
String expectedYAML = "openapi: 3.0.1\n" +
"paths:\n" +
" /users/add:\n" +
" post:\n" +
" operationId: addUser\n" +
" requestBody:\n" +
" content:\n" +
" application/x-www-form-urlencoded:\n" +
" schema:\n" +
" type: object\n" +
" properties:\n" +
" id:\n" +
" type: string\n" +
" name:\n" +
" type: string\n" +
" gender:\n" +
" type: string\n" +
" responses:\n" +
" default:\n" +
" description: default response\n" +
" content:\n" +
" application/json: {}";
compareAsYaml(UrlEncodedResource.class, expectedYAML);
}
@Test(description = "Test multipart")
public void testMultiPart() throws IOException {
String expectedYAML = "openapi: 3.0.1\n" +
"paths:\n" +
" /files/upload:\n" +
" post:\n" +
" operationId: uploadFile\n" +
" requestBody:\n" +
" content:\n" +
" multipart/form-data:\n" +
" schema:\n" +
" type: object\n" +
" properties:\n" +
" fileIdRenamed:\n" +
" type: string\n" +
" fileRenamed:\n" +
" type: string\n" +
" format: binary\n" +
" responses:\n" +
" default:\n" +
" description: default response\n" +
" content:\n" +
" application/json: {}\n";
compareAsYaml(MultiPartFileResource.class, expectedYAML);
}
}