post request with multiple parameters JSON and String on Jackson/Jersey JAVA - java

I've created a rest api using Jersey/Jackson and it works well. I want to adjust my POST methods to receive a string token in addition to the POJO they are receiving as JSON. I've adjusted one of my methods like so:
#POST
#Path("/user")
#Consumes(MediaType.APPLICATION_JSON)
public Response createObject(User o, String token) {
System.out.println("token: " + token);
String password = Tools.encryptPassword(o.getPassword());
o.setPassword(password);
String response = DAL.upsert(o);
return Response.status(201).entity(response).build();
}
I want to call that method, but for whatever reason token prints to null no matter what I try. Here is the client code I've written to send the post request:
public String update() {
try {
com.sun.jersey.api.client.Client daclient = com.sun.jersey.api.client.Client
.create();
WebResource webResource = daclient
.resource("http://localhost:8080/PhizzleAPI/rest/post/user");
User c = new User(id, client, permission, reseller, type, username,
password, name, email, active, createddate,
lastmodifieddate, token, tokentimestamp);
JSONObject j = new JSONObject(c);
ObjectMapper mapper = new ObjectMapper();
String request = mapper.writeValueAsString(c) + "&{''token'':,''"
+ "dog" + "''}";
System.out.println("request:" + request);
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class, request);
if (response.getStatus() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
setId(UUID.fromString(output));
System.out.println("output:" + output);
return "" + output;
} catch (UniformInterfaceException e) {
return "failue: " + e.getMessage();
} catch (ClientHandlerException e) {
return "failue: " + e.getMessage();
} catch (Exception e) {
return "failure: " + e.getMessage();
}
}
Any help would be greatly appreciated.

This is not the way JAX-RS works. The body of your POST request will get marshaled to the first argument of your annotated resource method (in this case, into the User argument). You have a couple options to get around this:
Create a wrapper object containing both a User object and token. Send that back and forth between your client and server.
Specify the token as a query parameter on your URL and access it on the server side as a #QueryParam.
Add the token as a header parameter and access it on the server side as a #HeaderParam.
Example - Option 1
class UserTokenContainer implements Serializable {
private User user;
private String token;
// Constructors, getters/setters
}
Example - Option 2
Client:
WebResource webResource = client.
resource("http://localhost:8080/PhizzleAPI/rest/post/user?token=mytoken");
Server:
#POST
Path("/user")
#Consumes(MediaType.APPLICATION_JSON)
public Response createObject(#QueryParam("token") String token, User o) {
System.out.println("token: " + token);
// ...
}
Example - Option 3
Client:
ClientResponse response = webResource
.type("application/json")
.header("Token", token)
.post(ClientResponse.class, request);
Server:
#POST
Path("/user")
#Consumes(MediaType.APPLICATION_JSON)
public Response createObject(#HeaderParam("token") String token, User o) {
System.out.println("token: " + token);
// ...
}

In case you're using Jersey 1.x, best approach is to post multiple objects as #FormParam
At least two advantages:
You don't need to use a wrapper object to post multiple parameters
The parameters are sent within the body rather than in the url (as with #QueryParam and #PathParam)
Check this example:
Client: (pure Java):
public Response testPost(String param1, String param2) {
// Build the request string in this format:
// String request = "param1=1&param2=2";
String request = "param1=" + param1+ "&param2=" + param2;
WebClient client = WebClient.create(...);
return client.path(CONTROLLER_BASE_URI + "/test")
.post(request);
}
Server:
#Path("/test")
#POST
#Produces(MediaType.APPLICATION_JSON)
public void test(#FormParam("param1") String param1, #FormParam("param2") String param2) {
...
}

Related

Passing authorities and user principal from rest client to server spring boot

I have to call one secured endpoint from rest client and at the controller side it require the authorities and user principal information to be sent from client.
String endpoint="http://localhost:8096/polygons/34";
// endpoint="https://dop-int.edosdp.ericsson.se/polygon-manager/polygons/34";
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("mahi", "ChangeM6");
headers.setConnection("keep-alive");
HttpEntity<String> httpEntity = new HttpEntity<String>(headers);
ResponseEntity<Long> exchange = restTemplate.exchange(endpoint,HttpMethod.GET, httpEntity, Long.class);
how can send at least one role(ADMIN or GUEST_USER) information from client .
IS there any way I can wrap up all user info in a dummy session and send it to the serer.
Thanks ,
Mahi
No! It's a bad idea for the client to modify any kind of session information including cookies. Only the server should be allowed to do that.
Since your requirement is to check for user role on a specific url, you can set a custom request header and check for it within the controller method itself:
Example code:
#GetMapping("/polygons")
public String getPolygons(HttpServletRequest request) {
String userRole = request.getHeader("user-role");
if(userRole != null && userRole.toLowerCase().equals("admin")) {
System.out.print("Role provided: " + userRole);
// ...
return "some-data";
}
System.out.print("Role not provided!");
return "error";
}
You could also set the user role in the request body for a post request.
public class RequestParams {
private String userRole;
// ...
}
#PostMapping("/polygons")
public String getPolygons(#RequestBody RequestParams requestParams) {
String userRole = requestParams.getUserRole();
if(userRole != null && userRole.toLowerCase().equals("admin")) {
System.out.print("Role provided: " + userRole);
// ...
return "some-data";
}
System.out.print("Role not provided!");
return "error";
}
If your requirement is to check for the user role on multiple urls then you should consider writing a servlet filter.
EDIT:
I think I too faced a similar situation in the past. I ended up using apache's httpclient library instead of resttemplate.
Here's some sample code:
private List<OrganizationDTO> getUserOrgUnits(String loggedInUserId, String token) {
List<OrganizationDTO> userList = new ArrayList<OrganizationDTO>();
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(getUserOrgUnitsApiURL());
try {
// Setting header
httpGet.setHeader("Authorization", "Bearer " + token);
httpGet.setHeader("Content-type", "application/json");
// Setting custom header
httpGet.setHeader(USERID_HEADER_NAME, loggedInUserId);
CloseableHttpResponse response = httpClient.execute(httpGet);
String result = EntityUtils.toString(response.getEntity());
JsonNode node = null;
ObjectMapper mapper = new ObjectMapper();
node = mapper.readTree(result);
Iterable<JsonNode> list = node.path("data");
for (JsonNode jsonNode : list) {
OrganizationDTO dto = mapper.treeToValue(jsonNode, OrganizationDTO.class);
userList.add(dto);
}
} catch (Exception e) {
log.error("getUserOrgUnits: Exception.");
e.printStackTrace();
}
return userList;
}

Changing a 404 response for REST API to a 200 empty response

I have a Spring Boot application written in Java that is a REST API. This service (Svc A) calls a REST API service (Svc B) with is also a Spring Boot Application written in Java. Svc B returns a 404 status code when no data was found. I need to change this response to a 200 status code and return an empty response object. I am not sure if or how to do this.
I can catch the error and determine if the 404 is this no data found error. However, I don't know how to change the response to a 200 empty response.
I am using a FeignClient to call the service. This is the error code that catches the 404:
#Component
public class FeignErrorDecoder implements ErrorDecoder {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Override
public Exception decode(String methodKey, Response response) {
Reader reader = null;
String messageText = null;
switch (response.status()){
case 400:
logger.error("Status code " + response.status() + ", methodKey = " + methodKey);
case 404:
{
logger.error("Error took place when using Feign client to send HTTP Request. Status code " + response.status() + ", methodKey = " + methodKey);
try {
reader = response.body().asReader();
//Easy way to read the stream and get a String object
String result = CharStreams.toString(reader);
logger.error("RESPONSE BODY: " + result);
ObjectMapper mapper = new ObjectMapper();
//just in case you missed an attribute in the Pojo
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//init the Pojo
ExceptionMessage exceptionMessage = mapper.readValue(result,
ExceptionMessage.class);
messageText = exceptionMessage.getMessage();
logger.info("message: " + messageText);
} catch(IOException ex) {
logger.error(ex.getMessage());
}
finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return new ResponseStatusException(HttpStatus.valueOf(200), messageText);
}
default:
return new Exception(response.reason());
}
}
}
I can change the status code to a 200 and it returns a 200 but I need to the response to have an empty response object.
The above code will return this response body of an error response object:
{
"statusCd" : "200",
"message" : "The Location not found for given Location Number and Facility Type Code",
"detailDesc" : "The Location not found for given Location Number and Facility Type Code. Error Timestamp : 2020-01-31 18:19:13"
}
I need it to return a response body like this:
200 - Empty Response
{
"facilityNumber": "923",
"facilityTimeZone": null,
"facilityAbbr": null,
"scheduledOperations": []
}
In case 404 just try
return new ResponseStatusException(HttpStatus.valueOf(200));
For anyone that has to do something this crazy...here is my solution:
Removed the FeignErrorCode file.
Added an exception to ControllerAdvice class like this:
#ExceptionHandler(FeignException.class)
public ResponseEntity<?> handleFeignException(FeignException fe, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), HttpStatus.valueOf(fe.status()), fe.getMessage(), request.getDescription(false));
String response = fe.contentUTF8();
if(response != null) {
ScheduledOperationsViewResponse scheduledOperationsViewResponse = new ScheduledOperationsViewResponse();
if (response.contains("Scheduled") || response.contains("Location")) {
HttpHeaders headers = new HttpHeaders();
scheduledOperationsViewResponse.setFacilityNumber(request.getParameter("facilityNumber"));
return new ResponseEntity<ScheduledOperationsViewResponse>(scheduledOperationsViewResponse, headers, HttpStatus.OK);
}
}
return new ResponseEntity<>(errorDetails, errorDetails.getStatus());
}

java rest web service by post method

I am trying to do a java rest web service using "POST" method.But i am unable to access the passed parameter. Here is my client part to invoke the web service.
public static void main(String[] args) {
try {
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8080/wsRevDash/rest/post/testing");
Form form=new Form();
form.add("sc","pqr");
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class,form);
if (response.getStatus() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output);
} catch (Exception e) {
e.printStackTrace();
}
}
And here is my java rest web service.
#POST
#Path("testing")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String createDataInJSON(#FormParam("sc") String data) {
System.out.println("Hello"+data);
JSONObject jObjDevice = new JSONObject();
jObjDevice.put("Hello",data);
return jObjDevice.toJSONString();
}
When i run on SoapUI,I am getting {"Hello":null}.
Please suggest me some way to cope with this.
Try changing form to a String:
String input = new Gson().toJson(form);
And pass in input to the response:
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class,input);
And amend your web service to something like:
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
public Response createDataInJSON(String data) {
String result = "Hello: " + data;
return Response.status(200).entity(result).build();
}
And you need to remove 'testing' from your initial path:
WebResource webResource = client.resource("http://localhost:8080/wsRevDash/rest/post/testing"); <---- here
And include a slash before it in the web service:
#Path("/testing")

Jax-rs Jeresy client gives nul values when I use query params to inject data

I am just new to JAX-RS. When I Use query params with post request in the client it is returning null values. Here is my code.
Resource WebService Code:
#Path("/user")
public class JSONService {
#POST
#Path("/add")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.APPLICATION_JSON)
public Response addUser(
#QueryParam("name") String name,
#QueryParam("age") int age) {
return Response.status(200).entity("addUser is called, name : " + name + ", age : " + age).build();
}
}
client code:
try {
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8080/simpleweb/rest/user").path("/add");
MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
queryParams.add("name", "arunkumar");
queryParams.add("age", "25");
ClientResponse response = webResource.type(MediaType.APPLICATION_FORM_URLENCODED).post(ClientResponse.class,queryParams);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
String output = response.getEntity(String.class);
System.out.println("============getCtoFResponse============");
System.out.println(output);
} catch (Exception e) {
e.printStackTrace();
}
}
The OutPut is :
============getCtoFResponse============
addUser is called, name : null, age : 0
Please Help me in this issue.Thanks
Use #FormParam instead of #QueryParam. The latter is for query string key/value pairs that go in the URL, e.g. /url?name=blah&age=2. #FormParam is for application/x-www-form-urlencoded entity data, which is what you're trying to send

Jersey converting from ClientResponse to Response

I'm currently using Jersey as a proxy REST api to call another RESTful web service. Some of the calls will be passed to and from with minimal processing in my server.
Is there a way to do this cleanly? I was thinking of using the Jersey Client to make the REST call, then converting the ClientResponse into a Response. Is this possible or is there a better way to do this?
Some example code:
#GET
#Path("/groups/{ownerID}")
#Produces("application/xml")
public String getDomainGroups(#PathParam("ownerID") String ownerID) {
WebResource r = client.resource(URL_BASE + "/" + URL_GET_GROUPS + "/" + ownerID);
String resp = r.get(String.class);
return resp;
}
This works if the response is always a success, but if there's a 404 on the other server, I'd have to check the response code. In other words, is there clean way to just return the response I got?
There is no convenience method as far as I am aware. You can do this:
public Response getDomainGroups(#PathParam("ownerID") String ownerID) {
WebResource r = client.resource(URL_BASE + "/" + URL_GET_GROUPS + "/" + ownerID);
ClientResponse resp = r.get(ClientResponse.class);
return clientResponseToResponse(resp);
}
public static Response clientResponseToResponse(ClientResponse r) {
// copy the status code
ResponseBuilder rb = Response.status(r.getStatus());
// copy all the headers
for (Entry<String, List<String>> entry : r.getHeaders().entrySet()) {
for (String value : entry.getValue()) {
rb.header(entry.getKey(), value);
}
}
// copy the entity
rb.entity(r.getEntityInputStream());
// return the response
return rb.build();
}
for me answer from Martin throw:
JsonMappingException: No serializer found for class sun.net.www.protocol.http.HttpURLConnection$HttpInputStream
Change from
rb.entity(r.getEntityInputStream());
to
rb.entity(r.getEntity(new GenericType<String>(){}));
helped.

Categories