Why my parameters are not getting passed to the RESTful web service? - java

I have this code using Angular 4 HttpClient, supposed to communicate with a simple RESTful JAVA web service and get a JSONstring back:
this.client.post('http://localhost:8080/ToDoService/rest/service/create', {id: 'foo', todo: 'bar'}).subscribe((data) => {
console.log("Got data: ", data);
}, (error) => {
console.log("Error", error);
})
It's not working. What I mean is that the id and todo parameters are not getting passed to the REST backend.
At the other hand, if I change above code to:
this.client.post('http://localhost:8080/ToDoService/rest/service/create?id=foo&todo=bar', '').subscribe((data) => {
console.log("Got data: ", data);
}, (error) => {
console.log("Error", error);
})
Everything works fine, but I'm sure the second snipped is wrong. It just looks wrong.
Could you give me a push and point my mistake?
P.s
The JAVA backend:
#Path("/service")
public class Rest extends Application{
#POST
#Path("/create")
public Response printMessage(#QueryParam("id") String userId, #QueryParam("todo") String toDo) {
JSONObject result = new JSONObject();
result.put("id", userId);
result.put("todo", toDo);
return Response.status(200).entity(result.toString()).build();
}
}

You're mapping QueryParams, you need to map that payload to either a Map or an Object:
class PayLoad {
private String id;
private String todo;
// Getter and Setters
}
#Path("/service")
public class Rest extends Application{
#POST
#Path("/create")
public Response printMessage(#RequestBody PayLoad payload) {
JSONObject result = new JSONObject();
result.put("id", payload.getId());
result.put("todo", payload.getTodo());
return Response.status(200).entity(result.toString()).build();
}
}
Hope this helps!

First of all, looking at the MyKong tutorial you can see that #QueryParam accepts parameters sent in the URL. That is a first problem here. Back to the main point.
I am not an expert in Angular 4, but I think the problem lies deeper in your architecture. You are sending to your backend:
{id: 'foo', todo: 'bar'}
and expect in your Java:
#QueryParam("id") String userId, #QueryParam("todo") String toDo
You pass an object and expect in your Java backend two strings. If you want to get your object, you might create this kind of class:
public class JsonWrapper {
private String id;
private String todo;
// Classic constructor and setters
}
Then, in your service:
#Path("/service")
public class Rest extends Application {
#POST
#Path("/create")
public Response printMessage(#RequestBody JsonWrapper wrapper) {
JSONObject result = new JSONObject();
result.put("id", wrapper.getId());
result.put("todo", wrapper.getTodo());
return Response.status(200).entity(result.toString()).build();
}
}
If the JsonWrapper does not work, I think a Map can do the trick, too.

Related

Issue with Spring Webflux webclient , nothing happens when trying to send post request

Have the following implementation of webclient :
public <T> WebClient.ResponseSpec sendRequest(HttpMethod method, String contentType, T body, String baseUrl, String path) {
try {
WebClient webClient = WebClient.builder().baseUrl(baseUrl).filter(logRequest()).build();
WebClient.ResponseSpec responseSpec = webClient.method(method)
.uri(path)
.header(HttpHeaders.CONTENT_TYPE, contentType)
.body(BodyInserters.fromObject(body))
.retrieve();
return responseSpec;
} catch (Exception e) {
throw new WebClientProcessingException("Exception when trying to execute request", e);
}
}
// This method returns filter function which will log request data
private static ExchangeFilterFunction logRequest() {
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
LOGGER.info("Request: {} {} {}", clientRequest.method(), clientRequest.url(), clientRequest.body());
clientRequest.headers().forEach((name, values) -> values.forEach(value -> LOGGER.info("{}={}", name, value)));
return Mono.just(clientRequest);
});
}
Also have the following code , which is creating user object and command which contains user object , then calling webclient to send an request
#Autowired
private BaseWebClient baseWebClient;
#Override
public void saveOrUpdateUser() {
UserPayload userPayload = new UserPayload();
userPayload.setUserId(111L);
userPayload.setCreatedAt(ZonedDateTime.now(DateTimeProps.systemTimeZone));
UserCommand userCommand = new UserCommand();
userCommand.setUser(userPayload);
baseWebClient.sendRequest(HttpMethod.POST, "application/json",
Stream.of(userCommand).collect(Collectors.toList()),
"http://localhost:8080",
"/users").onStatus(HttpStatus::isError, clientResponse -> {
throw new WebClientUserSaveOrUpdateeFailedException("Exception when trying to update user state")
.bodyToMono(String.class);
});
}
User payload :
#Data
#NoArgsConstructor
#AllArgsConstructor
public class UserPayload {
Long userId;
ZonedDateTime createdAt;
}
User command :
#Data
#NoArgsConstructor
#AllArgsConstructor
public class UserCommand {
#JsonProperty("user")
UserPayload user;
}
Json which is waiting for my other app (whom I am sending a request) :
[
{ "user":
{
"userId": 1,
"createdAt": "2019-05-16T08:24:46.412Z"
}
}
]
Using : Spring boot 2 , Lombok (for getter/setter) , gradle
When I'm trying to send a request nothing happens. No exception even.
I tried with very simple case as well the same issue.
One more note, is it possible to log body? I mean somehow see final json
I guess I am missing something general.
In Reactor, nothing happens until you subscribe. retrive() does not actually start the request. As you can see in the example, you should use one of the method to convert the ResponseSpec to a Publisher and then eventually subscribe to that publisher.
Depending on how you're using this method, you might be able to let Spring subscribe to the publisher instead. WebFlux supports reactive types in the model which means you can directly return a Mono from your RestController methods, for example.

Spring MVC - The request sent by the client was syntatically incorrect

I have a simple controller:
#RequestMapping(method = { RequestMethod.POST })
public ResponseEntity<MyResponse> print(#RequestBody final RequestModel request) throw ApiException {
return null;
}
And in my RequestModel:
class RequestModel {
private String name;
private CustomData data;
}
CustomData:
class CustomData {
private String data;
}
When I make POST request without the "data" field, it works. But if I add the "data" field, I'm getting a 400, The request sent by the client was syntatically incorrect.
O dont know If you wrote all the code, but tou should implements serializable and write setters and getters.
But, answering your question, you should annotate your fields with #JsonProperty to specify the required flag.
Your posted JSON should be something like this :
{
"name":"Luke",
"data": {
"data":"I am your father"
}
}
OBS: if you are using Postman, please set the header : key: Content-Type, value: application/json
You should specify an endpoint:
Example :
#PostMapping("/data")
Instead of
#RequestMapping(method = { RequestMethod.POST })
If you are using default port, try again the post to :
http://localhost:8080/data
OBS: RequestModel and CustomerData must have getters and setters.

XMLRootElement failing for DELETE in JAVA Jersey RESTful

Ok, so I am building a RESTful service in Java using Jersey.
I have implemented the POST which works wonderfully, which creates a new row in the Category table in my Database. Now when I try to do the DELETE, I pass it the same row in JSON, but it returns a "400: Bad Request - the request cannot be fulfilled due to bad syntax".
I am confused, since the JSON is copied and pasted from the result I get when I do a GET on that specific category.
Here is the relevant code:
#Path("/categories/")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class CategoryResource {
#POST
public Response addCategory(Category category, #Context UriInfo uriInfo)
{
JSONArray json_array = category_service.addCategory(category);
URI uri = uriInfo.getAbsolutePathBuilder().path(category.getCategory_name()).build();
return Response.created(uri)
.status(Status.CREATED)
.entity(json_array.toString())
.build();
}
#DELETE
public Response deleteCategory(Category category)
{
System.out.println("Category = " + category.toString());
category_service.deleteCategory(category);
return Response.ok().build();
}
The system.out.println() is never executed because it seems like it fails to do the encoding of the category. The Category class is here, replete with the usual getters and setters:
#XmlRootElement
public class Category {
private int category_id;
private String category_name;
private boolean child;
private int parent_id;
private boolean category_state;
private String category_reason;
public Category() {
}
The JSON that is being passed in the raw looks like this:
{
"category_id": 1,
"category_name": "tennis",
"child": true,
"parent_id": 4,
"category_state": true,
"category_reason": "I Like Tennis"
}
Note that this has been copied and pasted from the result of the GET....
So as was made clear in the comments by peeskillet, with a DELETE you don't give any body.

How to get JSON in Java REST / AngularJS frontend

Can someone please help me how to get a JSON String in a Webservice. I's sending JSON to my /api/register that looks like:
{"name":"MyName","surname":"MySurename","email":"mail#asd.de","street":"MyStreet","number":"3","zip":"12345","city":"myCity","pass":"myPassword"}
Here is my register.java file:
#Path("/register")
#Stateless
public class RegisterWS {
#EJB
UserBS userBS;
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void createUser(){
// code to get data from json
userBS.createUser(name, surename, email, adress, number, zip, city, password);
}
}
My AngularJS Controller and Service. The Data comes from a form, that is parsed to a JSON object.
app.service('RegisterService', function ($http) {
return {
registerUser : function(user) {
$http.post('http://localhost:8080/myApp/api/register')
.success(function (user) {
return user;
})
.error(function (data) {
// failed
});
}
}
});
app.controller('RegisterCtrl', function($scope, RegisterService) {
$scope.register = function(){
RegisterService.registerUser(angular.toJson($scope.user));
}
});
You should have a POJO, which maps to the received JSON object, for example a User class. In this case this would be a very simple Java Bean, with mostly String properties for each field in the JSON.
#XmlRootElement
public class User {
String name;
String surname;
String email;
String street;
Integer number;
String zip;
String city;
String pass;
}
Of course you would use private fields, with getters and setters, but I did not want to add clutter. By the way the #XmlRootElement is a JAXB annotation, and JAX-RS uses JAXB internally.
After you have this, you just need to change your method like this
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void createUser(User user) {
...
}
You should not need to change anything on the AngularJS side, as the default for the $http.post method is JSON communication.
For your Java code, you have to add a User POJO, I dont know if you will use some persistence API or not, so the user POJO must implement serializable to output user object as JSON.
Here's a an example of REST app with EJB ... : http://tomee.apache.org/examples-trunk/rest-on-ejb/README.html
For your client app, you need to specify the content type : "Content-Type" = "application/json"
See this questions: change Content-type to "application/json" POST method, RESTful API

Web Service accepting Object[]. What JSON it accepts?

I am writing a web service which should accept type Object[]. Its universal and needs to accept different number and types of parameters in different scenarios.
Request object looks like this:
#XmlRootElement
public class SimilarityRequest {
private Object[] params;
private String similarity;
public Object[] getParams() {
return params;
}
public void setParams(Object[] params) {
this.params = params;
}
public String getSimilarity() {
return similarity;
}
public void setSimilarity(String similarity) {
this.similarity = similarity;
}
}
This is WebService:
#SessionScoped
#Path("/similarity/")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Stateful
#StatefulTimeout(600000) // 10 minutes
public class SimilarityResource {
#POST
#Path("/")
public List<SimilarityResult> universalSimilarity(JAXBElement<SimilarityRequest> sr) {
Object[] params = sr.getValue().getParams();
String similarity = sr.getValue().getSimilarity();
}
}
I dont know what json it accepts for params in this case? I tried "params":{5,10} and "params":{"0":5,"1":10} and also "params":[5,10]. Something throws 500 and something 400 (bad request). Any ideas?
I've successfully implemented the service using Jersey, the code is the same, I've just removed the JAXBElement wrapper and the #XmlRootElement annotation.
The WEB-INF.xml file must include the folder containing the SimilarityRequest class in the
com.sun.jersey.config.property.packages parameter section and the com.sun.jersey.api.json.POJOMappingFeature parameter must be true.
The service receives correctly the following json:
{ "similarity": "test", "params":[5,10] }
The object array contains two Integer values.

Categories