I am facing a problem while trying to process a POST request via POSTMAN.
In my controller I have :
#ApiOperation(value = "xxxx", notes = "xxxx", response =
String.class, authorizations = {
#Authorization(value = "basicAuth")
}, tags={ "saveCourse", })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "successful operation", response =
String.class),
#ApiResponse(code = 404, message = "Not found", response =
String.class),
#ApiResponse(code = 405, message = "Invalid input", response =
String.class),
#ApiResponse(code = 500, message = "Internal Server Error", response =
String.class),
#ApiResponse(code = 200, message = "unexpected error", response =
String.class) })
#RequestMapping(value = "/course/saveCourse",
produces = { "application/json"},
consumes = { "application/json"},
method = RequestMethod.POST)
ResponseEntity<String> saveCourse(#ApiParam(value = "xxxxx" ,required=true ) #RequestBody Course coure){
LOG.info(course.toString);
}
Class Course :
public class Course implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#JsonProperty("prof")
private Prof prof = null;
#JsonProperty("students")
private List<Strudent> students = new ArrayList<Strudent>();
// getters & setters
// ...
}
class Prof :
public class Prof implements Serializable {
#JsonProperty("profLastName")
private String profLastName = null;
#JsonProperty("profFirstName")
private String profFirstName = null;
#JsonProperty("age")
private int age = null;
// getters & setters
}
class Student :
public class Student implements Serializable {
#JsonProperty("studentId")
private String studentId = null;
#JsonProperty("studentName")
private String studentName = null;
#JsonProperty("studAge")
private int studAge = null;
// getters & setters
// ...
}
in POSTMAN I am sending a POST request with the header :
Content-Type : application/json
the body :
{
"prof": {
"profLastName":"test",
"profFirstName":"test",
"age":"30"
},
"students" :[
"{'studentId':'0','studentName':'','studAge':'00'}",
"{'studentId':'2','studentName':'','studAge':'21'}",
"{'studentId':'4','studentName':'','studAge':'40'}",
"{'studentId':'6','studentName':'','studAge':'60'}"
]
}
When I process the request I am getting the RequestBody null :
[http-nio-xxxx-exec-4] INFO com.test.myControllerIml - class Course {
prof: null
students: []
}
you request body is wrong
you should use
{
"prof": {
"profLastName":"test",
"profFirstName":"test",
"age":"30"
},
"students" :[
{"studentId":"0","studentName":"","studAge":"00"},
{"studentId":"2","studentName":"","studAge":"21"},
{"studentId":"4","studentName":"","studAge":"40"},
{"studentId":"6","studentName":"","studAge":"60"}
]
}
Related
I'm using OpenApi Swagger UI (v. 4.14) with SpringBoot. I'm getting all the info I need with the Swagger, except for the exception. Here's my code.
Garage class:
#Schema(description = "Details about the Car")
#Document("Garage")
public class Garage implements Serializable {
#Schema(description = "An ID of the car in the database", accessMode = Schema.AccessMode.READ_ONLY)
#Id
private String id;
#Schema(description = "The name of the car")
#Field("model")
protected String carModel;
#Schema(description = "Car's engine power output")
protected Integer hp;
#Schema(description = "Production year of the car")
#Field("Year")
protected Integer year;
#Schema(description = "The name of car's designer")
protected String designer;
// controllers, getters, setters, toString
Controller:
// some other code
#Operation(summary = "Deletes a car by its id")
#ApiResponses(value = {
#ApiResponse(responseCode = "200",
description = "A car is deleted from the Garage",
content = {#Content(
schema = #Schema(implementation = Garage.class),
mediaType = "application/json")}),
#ApiResponse(responseCode = "404",
description = "A car with this id is not in our garage",
content = #Content(
schema = #Schema(implementation = RestExceptionHandler.class),
mediaType = "application/json"))})
#DeleteMapping(path = "/deleteCar/{carId}")
public void deleteCarFromGarage(#PathVariable("carId") String id) {
garageService.deleteFromGarage(id);
}
// some other code
Exception handler:
#Schema(description = "Exception handling")
#RestControllerAdvice
public class RestExceptionHandler {
#Schema(description = "The ID is not valid")
#ExceptionHandler(value = {IllegalArgumentException.class})
public ResponseEntity<Object> resourceNotFoundException(IllegalArgumentException exception) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(exception.getMessage());
}
}
I'm getting 200 responses every time, no matter do I delete a correct id, or an incorrect one.
EDIT: here's my deleteFromGarage method
public void deleteFromGarage(String id) {
garageRepository.deleteById(id);
}
I've edited my deleteFromGarage method, and that solved the issue
deleteFromGarage before:
public void deleteFromGarage(String id) {
garageRepository.deleteById(id);
}
deleteFromGarage now:
public void deleteFromGarage(String id) {
if (garageRepository.findById(id).isEmpty()) {
throw new IllegalArgumentException("The ID is not valid");
} else {
garageRepository.deleteById(id);
}
}
My SpringBoot app has the following OpenAPI generated code.
In my RestController I have a custom ConstraintValidator #ValidIndexName on the indexName path parameter.
Why does the ConstraintValidator IndexNameValidator code below not get called?
I have the spring-boot-starter-validation dependency in my pom.
#javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2020-03-23T16:08:36.286420Z[Europe/London]")
#Validated
#Api(value = "Document", description = "the Document API")
public interface DocumentApi {
#ApiOperation(value = "", nickname = "createDocument", notes = "", tags={ "Document", })
#ApiResponses(value = {
#ApiResponse(code = 202, message = "Accepted") })
#RequestMapping(value = "/docs/{indexName}/",
consumes = { "application/json" },
method = RequestMethod.POST)
ResponseEntity<Void> _createDocument(#ApiParam(value = "Elasticsearch index name",required=true) #PathVariable("indexName") String indexName,#ApiParam(value = "" ) #Valid #RequestBody Document document);
#ApiOperation(value = "", nickname = "updateDocument", notes = "", tags={ "Document", })
#ApiResponses(value = {
#ApiResponse(code = 202, message = "Accepted") })
#RequestMapping(value = "/docs/{indexName}/",
consumes = { "application/json" },
method = RequestMethod.PUT)
ResponseEntity<Void> _updateDocument(#ApiParam(value = "Elasticsearch index name",required=true) #PathVariable("indexName") String indexName,#ApiParam(value = "" ) #Valid #RequestBody Document document);
}
#RestController
#Validated
public class DocumentApiImpl implements DocumentApi {
#Override
public ResponseEntity<Void> _createDocument(String indexName, Document document) {
return createDocument(indexName, document);
}
public ResponseEntity<Void> createDocument(#ValidIndexName String indexName, Document document) {
System.out.println("indexName = " + indexName);
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
#Override
public ResponseEntity<Void> _updateDocument(String indexName, Document document) {
return createDocument(indexName, document);
}
public ResponseEntity<Void> updateDocument(#ValidIndexName String indexName, Document document) {
System.out.println("indexName = " + indexName);
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
}
#Target( { PARAMETER })
#Retention(RUNTIME)
#Constraint(validatedBy = IndexNameValidator.class)
#Documented
public #interface ValidIndexName {
String message() default "TenantId cannot be used as an index name.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
#Component
public class IndexNameValidator implements ConstraintValidator<ValidIndexName, String> {
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
System.out.println("Validating value = " + value);
if (StringUtils.isEmpty(value)) {
return false;
}
return true;
}
}
I have a problem with valid request in kotlin because I currently have an object composed of a list of integers and another entity called emailData, when I send incomplete or in error format emaildata, the validation does not happen and let me enter the controller. my code this and my request in postman these
fun sendMessage(#Valid #RequestBody notificationData: NotificationData) {
this.notificationManager.sendNotificationByType(notificationData)
}
data class NotificationData(
#get:NotEmpty
#get:NotNull
#field:NotNull
#Size(min = 2, max = 14)
#get:JsonProperty("notification_type")
var notificationType : List<Int> = listOf(),
#Valid
//# #field:NotEmpty(message = "SRTERST enter id")
#get:JsonProperty("email_data")
var emailData : EmailData = EmailData())
data class EmailData(
#NotNull
#get:NotEmpty
#get:JsonProperty("email_receiver")
var emailReceiver : List<String> = listOf(),
#NotNull
#get:NotEmpty
#get:JsonProperty("subject")
var subject : String = "",
#get:NotEmpty
#NotNull
#get:JsonProperty("template_id")
var templateId : String = "",
#get:NotEmpty
#NotNull
#get:JsonProperty("template_params")
var templateParams : HashMap<String, String> = HashMap())
when i send
{
"notification_type":["0"],
"email_data":{
"subject":"test",
"template_id":"d-1860fd6fa461449b88c578b124a0b331"
}
}
the validation for the emailData no work.
I have following post mapping.
#PostMapping(value = BULK_UPDATE)
#ApiOperation(value = "Bulk Update of Markets by pairs of Market Key and Tier Quantity Id", tags = "Bulk", code = 200)
#ApiImplicitParams({
#ApiImplicitParam(name = "MarketTierQuantityId", value = "List of Market Key and Tier Quantity Id pairs",
paramType = "body", allowMultiple = true, dataType = "MarketTierQuantityId", required = true) })
#ApiResponses({
#ApiResponse(code = 200, message = "Bulk update successful", response = MarketStatus.class, responseContainer = "List") })
#ResponseStatus(org.springframework.http.HttpStatus.OK)
public ResponseEntity<StreamingResponseBody> bulkUpdate(
#RequestParam(name = IGNORE_SYNC_PAUSE_FAILURE, required = false, defaultValue = "false")
#ApiParam(name = IGNORE_SYNC_PAUSE_FAILURE, value = "Ignore failure of the jobs pause command") boolean ignoreJobsPauseFailure,
#RequestBody #ApiParam(name = "MarketTierQuantityId", value = "List of Market Key and Tier Quantity Id pairs", required = true) List<MarketTierQuantityId> marketTierQuantities,
#RequestParam(name = MOVE_TO_PREAUTH_FLAG, required = false, defaultValue = "true")
#ApiParam(name = MOVE_TO_PREAUTH_FLAG, value = "Move new units to Preauth for the markets with active waitlists") boolean moveToPreauth) throws BusinessException {
String requestId = getRequestId();
boolean jobsPaused = pauseJobs(ignoreJobsPauseFailure);
return LoggingStopWatch.wrap(() -> {
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON)
.body(outputStream -> process(new SyncBulkProcessorHelper(outputStream),
marketTierQuantities, jobsPaused, requestId, moveToPreauth, LoggingStopWatch.create(LOGGER, "Bulk Update")));
});
}
and i have written the following test.
#RunWith(SpringRunner.class)
#WebMvcTest(BulkUpdateController.class)
#ContextConfiguration(classes = { BulkUpdateController.class, SharedExecutor.class })
#ActiveProfiles("dev")
public class BulkUpdateControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private BulkStatusService bulkStatusService;
#MockBean
private BulkMarketService bulkMarketService;
#MockBean
private HttpService httpService;
#MockBean
private RestClient restClient;
#MockBean
private BulkProcessorHelper helper;
#Test
public void test() throws Exception {
String request = TestHelper.getSerializedRequest(getBulkUpdateRequest(), MarketTierQuantityId.class);
mockMvc.perform(post("/bulkupdate").accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON)
.content(request)).andExpect(status().is4xxClientError());
}
public MarketTierQuantityId getBulkUpdateRequest() {
MarketTierQuantityId market = new MarketTierQuantityId();
market.setMarketKey("00601|PR|COBROKE|POSTALCODE|FULL");
market.setTierQuantityId("10");
return market;
}
Getting the following error, have tried every possible way to resolve it but doesnt help.
Request failed. Error response:
{\"responseStatus\":{\"errorCode\":\"BadRequest\",\"message\":\"JSON
parse error: Cannot deserialize instance of java.util.ArrayList out
of START_OBJECT token\",\"stackTrace\":\"BusinessException(JSON parse
error:
P.S -> new to JUnits and mocks
I'm using the swagger-codegen to create a spring-server.
I also used the .useDefaultResponseMessages(false)-attribute
as described in Swagger - Springfox always generates some response messages (401,403...) by default. How can I remove them?
SwaggerConfig.java:
public Docket customImplementation() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.basePackage("myrest.api"))
.build()
.directModelSubstitute(org.joda.time.LocalDate.class, java.sql.Date.class)
.directModelSubstitute(org.joda.time.DateTime.class, java.util.Date.class)
.apiInfo(apiInfo());}
related apipart: Api.java:
#ApiOperation(value = "", notes = "Returns all clouds from the system that the user has access to ", response = Cloud.class, responseContainer = "List", tags = {
"cloud",})
#ApiResponses(value = {
#ApiResponse(code = 200, message = "All clouds ", response = Cloud.class),
/*#ApiResponse(code = 401, message = "Authorization for this action is missing", response = Error.class),
#ApiResponse(code = 403, message = "Forbidden action", response = Error.class),
#ApiResponse(code = 500, message = "An unexpected Error occured", response = Error.class),*/
#ApiResponse(code = 504, message = "Server temporary not available", response = Error.class)})
#RequestMapping(value = "/clouds",
produces = {"application/json"},
method = RequestMethod.GET)
ResponseEntity<List<Cloud>> findClouds();
But the swagger-ui still looks like:
swagger-ui: ResponseMessageTable
So it seems .useDefaultResponseMessages(false) is not working.
How do I disable these default error responses?
#John Duskin
I changes the Docketinitialization,changed the #Controller to #Restcontroller but I still get the 404 Message by Get
different looking 404-Message
The generated Serverstubs from Swagger-Codegen looks like:
Api.java:
#Api(value = "clouds", description = "the clouds API")
public interface CloudsApi {
#ApiOperation(value = "", notes = "Returns all clouds from the system that the user has access to ", response = Cloud.class, responseContainer = "List", tags={ "cloud", })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "All clouds ", response = Cloud.class),
#ApiResponse(code = 401, message = "Authorization for this action is missing", response = Cloud.class),
#ApiResponse(code = 403, message = "Forbidden action", response = Cloud.class),
#ApiResponse(code = 500, message = "An unexpected Error occured", response = Cloud.class),
#ApiResponse(code = 504, message = "Server temporary not available", response = Cloud.class) })
#RequestMapping(value = "/clouds",
produces = { "application/json" },
method = RequestMethod.GET)
ResponseEntity<List<Cloud>> findClouds();
and the separated Controller:
#RestController
public class CloudsApiController implements CloudsApi {
#Autowired
private UserService userService;
#Autowired
private CloudService cloudService;
public ResponseEntity<List<Cloud>> findClouds() {
//do some magic
return new ResponseEntity<List<Cloud>>(cloudList, HttpStatus.OK);
}
[...]
}
Try to put the call to useDefaultResponseMessages after the build method in the Docket. I've updated your code to show what I mean.
Hope that helps.
public Docket customImplementation() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("myrest.api"))
.build()
.useDefaultResponseMessages(false)
.directModelSubstitute(org.joda.time.LocalDate.class, java.sql.Date.class)
.directModelSubstitute(org.joda.time.DateTime.class, java.util.Date.class)
.apiInfo(apiInfo());
}
To get the calls working on my machine I've put the ApiReponses with the Controller
#RestController
#RequestMapping("/my_model")
#ApiResponses(value = { #ApiResponse(code = 200, message = "OK"),
#ApiResponse(code = 500, message = "Rocks fell, everyone died.") })
Update
Are you putting the description on the method?
Here is what I have working on my project. Note the API Responses are attached to the controller.
#RestController
#RequestMapping("/my_model/gogo")
#ApiResponses(value = { #ApiResponse(code = 200, message = "OK"),
#ApiResponse(code = 500, message = "Rocks Fall") })
public class GoGoClass {
#RequestMapping(method = RequestMethod.POST)
#ApiOperation(value = "Description")
public void run(
#ApiParam(value = "Param1 description") #RequestParam(required = true) final String param1,
#ApiParam(value = "Param 2 description") final String param2)
throws ModelException {
// Do stuff
}
}
fixed the problem beside working ...
this was a Spring Annotation Problem.
In my SwaggerDocumentationConfig.java I added #EnableSwagger2 and everything works as wanted
#Configuration
#EnableSwagger2
public class SwaggerDocumentationConfig {
#Bean
public Docket customImplementation(){
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.basePackage("myrest.api"))
.build()
.directModelSubstitute(org.joda.time.LocalDate.class, java.sql.Date.class)
.directModelSubstitute(org.joda.time.DateTime.class, java.util.Date.class)
.apiInfo(apiInfo());
}
}