Required, request body is missing: public when I try loading Swagger - java

I am trying to access the swagger URL from my Spring-Boot application using the post request. But getting a 400-Bad request and it says the request body is missing. But the same request works fine in Postman.
Controller:
#RestController
public class IdVController {
#Autowired
private IdService idService;
#Autowired
protected FileUtility util;
/** The Constant STATUS. */
private static final String STATUS = "status";
/** The Constant SUCCESS. */
private static final String SUCCESS = "success";
/** The Constant SYSTEM. */
private static final String SYSTEM = "SYSTEM";
#RequestMapping(value ="/idApi")
public ResponseEntity<MarketPlaceResponse>
validateIdData(#RequestBody VerifyIdDTO verifyIdDTO) throws Exception {
JSONObject rawResponse = idService.validateId(verifyIdDTO);
IdVerifyEntity DTOResponse = (IdVerifyEntity)util.convertToEntity(rawResponse.toString(), IdVerifyEntity.class);
if (rawResponse.get(STATUS).equals(SUCCESS)) {
DTOResponse.setCreated_by(SYSTEM);
DTOResponse.setCreated_date(new
java.sql.Date(System.currentTimeMillis()).toString());
}
//return ResponseBuilder.buildResponse(DTOResponse);
MarketPlaceResponse response = new MarketPlaceResponse();
response.setResponse(DTOResponse);
return new ResponseEntity<MarketPlaceResponse>(response,HttpStatus.OK);
}
}
Request DTO:
public class VerifyIdDTO {
#NotBlank(message="Owner ID should not be empty")
private String id;
private String citizenship;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCitizenship() {
return citizenship;
}
public void setCitizenship(String citizenship) {
this.citizenship = citizenship;
}
}
I am contacting an external service by building URL and using GET from this POST method
this is the swagger URL
localhost:8080/idvalidationservice/swagger-ui.html
You can see the error message in this screenshot.

Related

RequestBody handling a JSON containing Strings and a List

I'm sending a post request from the client to the server. The body of the post request looks like this:
...
body: JSON.stringify
({
command: 'someString',
dataFields: setDataList()
})
...
while the "setDataList()" returns the following structure:
[ {…}, {…}, {…}, ..., {…} ]
[0: {type: "_header_", label: "upload"}
1: {type: "_image_", name: "data:image/jpeg;base64", value: "base64 encoded string", label: "someImage.JPG"}
2: {...}]
I'm having issues processing the content of the "dataFields" key at the server. Currently, the SpringBoot applicaiton looks like this:
#PostMapping(
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE},
produces = {MediaType.APPLICATION_JSON_VALUE})
public void postBody(#RequestBody ManageRequest manageRequest) {
...
}
and "ManageRequest" like this:
import java.util.List;
public class ManageRequest {
private String accountId;
private String command;
private String transactionId;
private List<String> dataFields;
public String getAccountId() {
return accountId;
}
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
public List<String> getDataFieldList() {
return dataFields;
}
public void setDataFieldList(List<String> dataList) {
this.dataFields = dataList;
}
}
I'm not experienced in handling such requests with Java. My goal would be to extract the content of the "dataFields" like this: "dataFields[0], dataFields[1], ..." and allocate them to a new List to add to a post request.
At the moment, the list seems to be empty when arriving at the end point.
Your problems is with the List.
The server is waiting for a List of Strings but you are sending a List of objects with fields that are Strings.
private List<String> dataFields; // This property is a List of string not a list of "dataFields"
You should create a class DataField and it would looks like this
public class DataField{
private String type;
private String label;
private String name;
.
.
.
}
And then in your ManageRequest class you should do like this:
public class ManageRequest {
private String accountId;
private String command;
private String transactionId;
private List<DataField> dataFields;
//Getter and setters
}

I'm recieving "Error while extracting response for type" when I try to return the JSON as an Object. How can I solve this?

I'm doing an API that consumes an external API (https://swapi.dev/), but I'm receving this error when I try to return the JSON converted to Object.
I'm trying to solve this for almost 12 hours without any success x_x
Error while extracting response for type [class [Lcom.starwarsapi.filmsapi.model.FilmModel;] and content type [application/json]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `[Lcom.starwarsapi.filmsapi.model.FilmModel;` from Object value (token `JsonToken.START_OBJECT`);
FilmController:
#RestController
#RequestMapping("/films")
public class FilmController {
#Autowired
private FilmService filmService;
#GetMapping
public List<FilmModel> getAllFilms() {
List<FilmModel> response = filmService.getAllFilms();
return response;
}
FilmModel:
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class FilmModel {
private FilmResultModel[] results;
}
FilmResultModel
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class FilmResultModel {
private String title;
#JsonProperty("episode_id")
private Integer episodeId;
#JsonProperty("opening_crawl")
private String description;
private String director;
private String producer;
#JsonProperty("release_date")
private String releaseData;
private String[] characters;
private String[] planets;
private String[] starships;
private String[] vehicles;
private String[] species;
private String created;
private String edited;
private String url;
FilmService:
public interface FilmService {
public List<FilmModel> getAllFilms();
}
FilmServiceImpl:
#Service
public class FilmServiceImpl implements FilmService {
#Value("${external.api.url}")
private String filmBaseUrl;
#Autowired
private RestTemplate restTemplate;
#Override
public List<FilmModel> getAllFilms() {
FilmModel[] result = restTemplate.getForObject(filmBaseUrl, FilmModel[].class);
List<FilmModel> films = Arrays.asList(result);
System.out.println(films);
return films;
}
PS¹: external.api.url = https://swapi.dev/api/films/?format=json
PS²: When I return getAllFilms as String, the program works:
#Override
public String getAllFilms() {
String result = restTemplate.getForObject(filmBaseUrl, String.class);
System.out.println(result);
return result;
}
But I need it to return as an object because later I'll try to create a PUT method to change the description of the movie.
try using FilmModel result = restTemplate.getForObject(filmBaseUrl, FilmModel.class);
FilmModel is just the outer wrapper object and contains the list of films.

How to Use DI to get a final variable as #PostMapping's path

I have a final class Constants, which holds some final data.
#Component
public final class Constants {
public final String TOKEN;
public final String HOST;
public final String TELEGRAM;
public Constants(#Value("${myapp.bot-token}") String token,
#Value("${myapp.host}") String host) {
this.TOKEN = token;
this.HOST = host;
this.TELEGRAM = "https://api.telegram.org/bot" + TOKEN;
}
}
The problem is that, when I want to use a variable as #PostMapping path, I faced this error:
Attribute value must be constant
#RestController
#RequestMapping
public class Controller {
private final Constants constants;
#Autowired
public Controller(Constants constants) {
this.constants = constants;
}
#PostMapping(constants.TOKEN)// Problem is here
public ResponseEntity<?> getMessage(#RequestBody String payload) {
return new ResponseEntity<HttpStatus>(HttpStatus.OK);
}
}
I've tried to load TOKEN in my controller class but faced the same issue.
#RestController
#RequestMapping
public class Controller {
#Value("${myapp.bot-token}") String token
private String token;
#PostMapping(token)// Problem is here
public ResponseEntity<?> getMessage(#RequestBody String payload) {
return new ResponseEntity<HttpStatus>(HttpStatus.OK);
}
}
When I do something like this the problem will gone. But I don't want to declare my token in source-code.
#RestController
#RequestMapping
public class Controller {
private final String TOKEN = "SOME-TOKEN";
#PostMapping(TOKEN)// No problem
public ResponseEntity<?> getMessage(#RequestBody String payload) {
return new ResponseEntity<HttpStatus>(HttpStatus.OK);
}
}
Can anyone please give me a solution to this?
Try to paste string with property path inside #PostMapping annotation. Like this
#GetMapping(value = "${app.path}")
public String hello() {
return "hello";
}
You can only use a constant (i.e. a final static variable) as the parameter for an annotation.
Example:
#Component
class Constants {
public final static String FACEBOOK = "facebook";
}
#RestController
class Controller {
#PostMapping(Constants.FACEBOOK)
public ResponseEntity<ResponseBody> getMessage(#RequestBody String payload) {
return new ResponseEntity<>(HttpStatus.OK);
}
}
You must use builder pattern(use Lombok for ease) and freeze the value that you are getting from the properties and then use that in your program.

Send Data from Angular to Springboot over POST

I am trying to send one json from my frontend angular project to the backend which is springboot.
It is the first time I am using these 2 technologies so I lack in experience.
I am not quite sure if my http post method in Angular is wrong or if my backend isn't listening to the data which are supposed to come.
I will attach both code parts so that you can help me. Thank you in advance!
Here is a picture of the chrome console:
Http Errorcode 404
http error image
Backend:
#RestController
#RequestMapping
#CrossOrigin(origins = "http://localhost:4200")
public class RequestController {
private RolesRequestRepository rolesRequestRepository;
#PostMapping("/sendrolesrequest")
void addRequest(#RequestBody RolesRequest rolesRequest) {
rolesRequestRepository.save(rolesRequest);
}
#GetMapping("/sendrolesrequest")
public List<RolesRequest> getRequests() {
return (List<RolesRequest>) rolesRequestRepository.findAll();
}
}
#Entity
public class RolesRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String requester = "";
private String recipient = "";
public RolesRequest(String recipient, String requester) {
this.recipient = recipient;
this.requester = requester;
}
public RolesRequest(){
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRequester() {
return requester;
}
public void setRequester(String requester) {
this.requester = requester;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
}
Here is the angular frontend part:
#Injectable()
export class RequestService {
sendRolesRequestUrl = 'sendrolesrequest'; // URL to web api
private handleError: HandleError;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError('RequestService');
}
sendRolesRequest (rolesRequest: RequestModel): Observable<RequestModel> {
//console.log("addRolesRequest try post:" + rolesRequest.print());
return this.http.post<RequestModel>(this.sendRolesRequestUrl, rolesRequest, httpOptions)
.pipe(
catchError(this.handleError('sendRolesRequest', rolesRequest))
);
}
testPost() {
const headers = new Headers();
headers.append('Content-Type', 'application/json; charset=utf-8');
this.http.post(this.sendRolesRequestUrl, {'key1': 'value1', 'key2': 'value2'}, httpOptions)
.subscribe(() => {}, err => console.error(err));
}
}
export class RequestFormulaComponent implements OnInit {
onSendRequest() {
this.requestService
.sendRolesRequest(this.rolesRequest)
.subscribe();
}
}
I would be very happy if someone helps me out here. I am struggling on this topic over a week.
Is that even the way how a backend application should communicate with the webpage? If not, how can I do it otherwise?
You're using JPA entity as DTO, and have no setters/getters, also there is no default constuctor, modify your RolesRequest like this:
#Entity
public class RolesRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String requester = "";
private String recipient = "";
public RolesRequest() { }
public RolesRequest(String recipient, String requester) {
this.recipient = recipient;
this.requester = requester;
}
public String getRequester() { return this.requester; }
public void setRequester(String r) { this.requester = r;}
public String getRecipient() { return this.recipient; }
public void setRecipient(String r) { this.recipient = r;}
Are your backend and angular app running on the same port? (backend and frontend are combined in the same application)
You are calling http://localhost:4200/sendrolesrequest and I think that's a request on the Angular app itself. You get a HTTP 404 error code (NOT FOUND)
You should call the endpoint of the backend application. It's running on port 8080 for example so call http://localhost:8080/sendrolesrequest (or with other port if backend is running on another port)
Change:
sendRolesRequestUrl = 'sendrolesrequest';
to:
sendRolesRequestUrl = 'http://localhost:8080/sendrolesrequest';

Dynamic Request body REST API Method using swagger

I have use case were I need to get requestBody based on selection of field.below is same code which I was able get the dynamic responseBody Based on selection ProtocolType.Is there is any way that swagger can read the RequestBody Dynamically.
Controller.Java
#ApiOperation(value = "Protocol Account", tags = {"ProtocolAccount"})
#RequestMapping(value = "/protocolAccount/{protocolName}",
method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody public ProtocolAccount getProtocol(#PathVariable String protocolName)
{
return service.getProtocol(protocolName);
}
Service.Java
public ProtocolAccount getProtocol(String protocolName){
ProtocolAccount protocolAccount=new ProtocolAccount();
Object object=ProtocolType.fromMap(protocolName);
protocolAccount.setProtocol(object);
return protocolAccount;
}
POJOs
public class ProtocolAccount
{
String Id;
private Object protocolType
}
public class Protocol{
private String port;
}
public class FTPProtocol extends Protocol{
/*Some Fields*/
}
public class SFTPProtocol extends Protocol{
/*Some Fields*/
}
Enumeration
public enum ProtocolType
{
SFTP("SFTP"), FTPS("FTPS"), AS2("AS2"), FTP("FTP");
private final String value;
private static final EnumMap<ProtocolType,
Object>map = new EnumMap<ProtocolType, Object>(ProtocolType.class);
static{
map.put(ProtocolType.SFTP, new SFTPProtocol());
map.put(ProtocolType.FTP, new FTPProtocol());
map.put(ProtocolType.FTPS,new FTPSProtocol());
}
ProtocolType(String v){
value=v;
}
public static ProtocolType fromValue(String val){
return EnumSet.allOf(ProtocolType.class)
.stream().filter(e->e.value.equals(val))
.findFirst().orElseThrow(()->new IllegalArgumentException(val));
}
public String value(){
return value;
}
public static Object fromMap(String value)
{
return map.get(ProtocolType.fromValue(value));
}
}

Categories