How to send JSON data in request body suing apache CXF webclient? - java

I am using apache cxf webclient to consume a service written in .NET
sample JSON to be sent in request body to a web service
{
"Conditions":
[
{
"Field":"TextBody",
"Comparer":"ContainsAny",
"Values":["stocks","retire"],
"Proximity":0
},
{
"Field":"SentAt",
"Comparer":"LessThan",
"Values":["1331769600"],
"Proximity":0
},
],
"Operator":"And",
"ExpireResultIn":3600
}
Is there any way if I want to submit data from both form and in Json body in one request ?
webclient API apache CXF -
web client API doc
WebClient client = WebClient.create("http://mylocalhost.com:8989/CXFTest/cxfws/rest/restservice/json");
client.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
After this which method and how to use ?
client.form(...form object )
client.post(...JSON string )
They have not shared Object of "Conditions" in JSON which I can annotate and pass to post method of client

I got answer here
Need to set JSON provider in my case it was jackson
List<Object> providers = new ArrayList<Object>();
providers.add( new JacksonJaxbJsonProvider() );
WebClient client = WebClient.create("http://localhost:8080/poc_restapi_cxf/api",
providers);
client = client.accept("application/json")
.type("application/json")
.path("/order")
.query("id", "1");
Order order = client.get(Order.class);
System.out.println("Order:" + order.getCustomerName());

There is a way to do this using annotations and suited my purpose:
#Post
#Path("mypath/json/whatever")
#Consumes({MediaType.APPLICATION_JSON_VALUE})
public Response postClient(#Context HttpHeaders headers, String input) {
//Here the String input will be equal to the supplied json.
//...
}

Related

Filtering response using webclient

I'm new using webclient to cosume a Rest API and I want to know how can I filter a response to match only what I want.
So I have this endpoint which brings me a customerById but I need to show only the the systemsId = 100
Let me show:
#GetMapping("/getCucoId/{cucoId}")
public Mono<CuCoPerson> getCucoRelationById(#PathVariable Integer cucoId) {
WebClient webClient = WebClient.create();
return webClient.get()
.uri(GET_RELATION_BY_ID + cucoId)
.header("Accept", "application/json")
.header("Authorization", "Bearer eyJraWQiOi.....")
.retrieve()
.bodyToMono(CuCoPerson.class);
}
And the POJO:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CuCoPerson {
private Integer cucoID;
private List<CustomerRelation> relatedCustomers;
}
And this is the response in Postman:
{
"cucoID": 100288298,
"relatedCustomers": [
{
"customerId": "F6305957",
"systemId": 100
},
{
"customerId": "F8364917",
"systemId": 400
},
{
"customerId": "F4194868",
"systemId": 101
}
]
}
So I need only to show the relatedCustomers who only have a systemID = 100
Thanks in advance!
I think you are looking for either Mono.map(), or Mono.flatMap().
Remove the customers, who don't match in the function, and return the changed object.
#GetMapping("/getCucoId/{cucoId}")
public Mono<CuCoPerson> getCucoRelationById(#PathVariable Integer cucoId) {
WebClient webClient = WebClient.create();
return webClient.get()
.uri(GET_RELATION_BY_ID + cucoId)
.header("Accept", "application/json")
.header("Authorization", "Bearer eyJraWQiOi.....")
.retrieve()
.bodyToMono(CuCoPerson.class)
.map(cuCoPerson -> {
List<CustomerRelation> matches = cuCoPerson.getRelatedCustomers()
.stream()
.filter(relation -> relation.getSystemId().equals(100))
.collect(Collectors.toList());
cuCoPerson.setRelatedCustomers(matches);
return cuCoPerson;
});
}
As mentioned in other answers, doing this kind of filtering on client side is bad practice. If possible the API should expose parameter for systemId and return only the data you need.
First of all this is bad Backend design. Since you (client side) have the need for such info you should have an endpoint available to get your info by customer ID and System ID. Data filtering should be done on the backend and the client should remain as thin as possible. Otherwise you perform logic both on server-side and client-side plus you send some completely unneeded info over the network and then filter it out on the client side. But if that's your available resources and you can't change the server-side then you you take your JSON response, and parse it into your class that maps to that JSON or just into Map<String,Object> if you don't have the class for that JSON and filter it out yourself. To parse a json string to map or a specific POJO you can use Jackson library - method readValue() of ObjectMapper Or Gson library. Also, I wrote my own simple wrapper over Jackson library that simplifies the use. Class JsonUtils is available as part of MgntUtils library (written and maintained by me). This class just has the methods that allow you to parse and de-serialize from/to Json String from/to a class instance. Here is a simple example on how to parse your JSON string into a Map<String,Object> with JSONUtils class
Map<String,Object> myMap
try {
myMap = JsonUtils.readObjectFromJsonString(myJsonStr, Map.class);
} catch(IOException ioe) {
....
}
MgntUtils library available as Maven artifact and on Github (including source code and Javadoc)
it could be something like this:
return webClient.get()
.uri("/someUrl")
.header("Accept", "application/json")
.header("Authorization", "Bearer eyJraWQiOi.....")
.retrieve()
.bodyToFlux(CuCoPerson.class)
.filter(cuCoPerson -> cuCoPerson.getRelatedCustomers().stream().anyMatch(cr -> cr.getSystemId() == 100))
.take(1)
.next();
But this has disadvantage that you are filtering the results on client side (your application). I would try to ask the api provider if s/he is able to provide filter parameter (something like systemId) and in that case you would call the endpoint with that query param.

Post request to external service with data in Springboot

I need to send post request to external service with data. How can I achieve that in Springboot.
For example - need to connect and send a request to endpoint a 10.20.30.111:30 with some data. Then that data will be tested and send back test result as response.
I am new to java and did some research but did not get any success.
You can check HttpClient
URI uri = URI.create("10.20.30.111:30/endpoint");
HttpRequest req = HttpRequest.newBuilder().uri(uri).build();
HttpResponse<String> response = httpClient.send(req,HttpResponse.BodyHandlers.ofString());
String body = response.body();
If the response is json, you can convert the String response body to a custom object using JSONB.
Jsonb jsonb = JsonBuilder.create();
MyDataClass myDataObject = jsonb.fromJson(body, MyDataClass.class);
Check the Feign Client:
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html
Your POST request will be implemented by an Interface like:
#FeignClient("stores")
public interface StoreClient {
#RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
Store update(#PathVariable("storeId") Long storeId, Store store);
}

how to support our own data formate in rest jaxrs to excahnge between client and server

i want to support our own data formate like cvv in restful service jaxrs
example
#GET
#Produces(MediaType.OurType)
public Response get(query() int awbn) {
Response response = null;
smaple sa=new sample();
response = Response.ok().entity(sa).build();
return response;
}
Since you are using JAX-RS to implement the web service, you can specify a custom Media Type and it should work out of the box.
Try:#Produces("application/YourCustomMediaType").

Spring Rest Template calls in java

Hi I am trying to call some Soft layer APIs and was able to make simple calls as well as calls which include passing some ids using Spring's RestTemplate in java, but not able to make a similar call in java for below rest URL.
// formatted for readability
https://getInvoices?
objectFilter={
"invoices":{
"createDate":{
"operation":"betweenDate",
"options":[
{
"name":"startDate",
"value":[
"06/01/2016"
]
},
{
"name":"endDate",
"value":[
"06/02/2016"
]
}
]
}
}
}
Can anyone help me out how to do the same in java using springs rest template or even using soft layer rest client.
If you are willing to user Jersey Client API, your code could be like:
String json = "{\"invoices\":{\"createDate\":{\"operation\":\"betweenDate\",\"options\":[{\"name\":\"startDate\",\"value\":[\"06/01/2016\"]},{\"name\":\"endDate\",\"value\":[\"06/02/2016\"]}]}}}";
Client client = ClientBuilder.newClient();
WebTarget target = client.target("https://api.softlayer.com")
.path("rest")
.path("v3")
.path("SoftLayer_Account")
.path("getInvoices")
.queryParam("objectFilter",
URLEncoder.encode(json, StandardCharsets.UTF_8.toString()));
String result = target.request(MediaType.APPLICATION_JSON_TYPE).get(String.class);
With Spring RestTemplate, you would do:
String json = "{\"invoices\":{\"createDate\":{\"operation\":\"betweenDate\",\"options\":[{\"name\":\"startDate\",\"value\":[\"06/01/2016\"]},{\"name\":\"endDate\",\"value\":[\"06/02/2016\"]}]}}}";
RestTemplate restTemplate = new RestTemplate();
URI targetUrl = UriComponentsBuilder
.fromUriString("https://api.softlayer.com")
.path("rest")
.path("v3")
.path("SoftLayer_Account")
.path("getInvoices")
.queryParam("objectFilter",
URLEncoder.encode(json, StandardCharsets.UTF_8.toString()))
.build()
.toUri();
String result = restTemplate.getForObject(targetUrl, String.class);
You can either use RestTemplate
RestTemplate restTemplate = new RestTemplate();
String resourceUrl = "http://localhost:8080/resturl";
ResponseEntity<String> response = restTemplate.getForEntity(resourceUrl+ "/1", String.class);
or you can go with httpclient

Apache CXF - http-centric approach and PUT from client to server

I use Apache CXF to provide communication with a RESTful API.
I need to use a PUT method to send some constrained entities to database via the API.
Is this the right way to provide this method?
I ask because I am getting a HTTP 500 error code response.
I can only find GET method examples in the official Apache CXF documentation; HTTP PUT, HTTP POST etc. are missing.
WebClient client =
WebClient.create("http://MY_SERVER:9090/admission/services/processing");
Admission a = new Admission();
a.setCode("73935282");
:
:
Response r = client.path("/admission").put(a);
// Here I would like to get 201, but there is 500 :(
System.out.println("response: " + r.getStatus());
Could it be that the service is expecting content type other than XML, like JSON? The default behavior for WebClient is to assume content-type is application/xml.
Here's the relevant source code for WebClient.java:
protected Response doInvoke(String httpMethod, Object body, Class<?> responseClass, Type genericType) {
MultivaluedMap<String, String> headers = getHeaders();
if (body != null) {
if (headers.getFirst(HttpHeaders.CONTENT_TYPE) == null) {
headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_TYPE.toString());
}
} else {
headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD);
}
if (responseClass != null && headers.getFirst(HttpHeaders.ACCEPT) == null) {
headers.putSingle(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_TYPE.toString());
}
resetResponse();
return doChainedInvocation(httpMethod, headers, body, responseClass, genericType, null, null);
}
If so, you can set the content type on WebClient using the type() method. For example, to have the client produce JSON:
WebClient client = WebClient.create("http://MY_SERVER:9090/admission/services/processing");
client.type(MediaType.APPLICATION_JSON_TYPE);
Admission a = new Admission();
a.setCode("73935282");
Response r = client.path("/admission").put(a);

Categories

Resources