how to POST Json object to a webservice - rest

I am trying to consume a webservice and post the JSON object as request in my program. JSON is nested.
{
"paymentorder": {
"operation": "Purchase",
"currency": "NOK",
"amount": 15610,
"vatAmount": 3122,
"description": "Test Purchase",
"userAgent": "Mozilla/5.0...",
"language": "nb-NO",
"urls": {
"hostUrls": ["https://localhost:9002", "https://powertools.local:9002"],
"completeUrl": "https://powertools.local:9002/payment-completed",
"cancelUrl": "https://powertools.local:9002/payment-canceled",
"callbackUrl": "https://powertools.local:9002/payment-callback",
"termsOfServiceUrl": "https://powertools.local:9002/termsandconditoons.pdf"
},
"payeeInfo": {
"payeeId": "20f3341c-e570-40a1-b76f-5347f4866de8",
"payeeReference": "P4555334",
"payeeName": "Kiran Vemula",
"productCategory": "P00432101",
"orderReference" : "P45553234"
},
"payer": {
"consumerProfileRef": "63adb0760ebdcca15d8475773a59c3f3b03df6222dfcc9f5740ce1eb3465f58e"
}
}
}
the build the Hashmaps like below:
private Map<String, Object> initiatePaymentMenuRequestBody(){
final Map<String, Object> paymentorderChilds = new LinkedHashMap<String, Object>();
paymentorderChilds.put("operation", "Purchase");
paymentorderChilds.put("currency",currency);
paymentorderChilds.put("amount",amount);
paymentorderChilds.put("vatAmount",vatAmount);
paymentorderChilds.put("description",description);
paymentorderChilds.put("userAgent",userAgent);
paymentorderChilds.put("language",language);
paymentorderChilds.put("urls", initiatePaymentMenuURLs());
paymentorderChilds.put("payeeInfo", initiatePaymentMenuPayeeInfo());
paymentorderChilds.put("payer", initiatePaymentMenuPayer());
return paymentorderChilds;
}
private Map initiatePaymentMenuURLs(){
final Map<String, Object> initiatePaymentMenuURLs = new LinkedHashMap<String, Object>();
List<String> hostUrls = new ArrayList<>();
hostUrls.add(mediqHostUrls1);
hostUrls.add(mediqHostUrls2);
initiatePaymentMenuURLs.put("hostUrls",hostUrls);
initiatePaymentMenuURLs.put("completeUrl",completeUrl);
initiatePaymentMenuURLs.put("cancelUrl",cancelUrl);
initiatePaymentMenuURLs.put("callbackUrl",callbackUrl);
initiatePaymentMenuURLs.put("termsOfServiceUrl",termsOfServiceUrl);
return initiatePaymentMenuURLs;
}
// implement this method with the real data from B2CCustomer and Cart object
private Map initiatePaymentMenuPayeeInfo(){
Map<String, String> initiatePaymentMenuPayeeInfo = new LinkedHashMap<String, String>();
initiatePaymentMenuPayeeInfo.put("payeeId",metchantID);
initiatePaymentMenuPayeeInfo.put("payeeReference",payeeReference);
initiatePaymentMenuPayeeInfo.put("payeeName",payeeName);
initiatePaymentMenuPayeeInfo.put("productCategory",productCategory);
initiatePaymentMenuPayeeInfo.put("orderReference",orderReference);
return initiatePaymentMenuPayeeInfo;
}
private Map initiatePaymentMenuPayer(){
Map<String, String> initiatePaymentMenuPayer = new LinkedHashMap<String, String>();
initiatePaymentMenuPayer.put("consumerProfileRef", initiateConsumerSession());
return initiatePaymentMenuPayer;
}
and finally calling the webservice to post the data:
#Override
public String initiatePaymentMenu(PaymentOrder paymentOrder1) {
final RestTemplate restTemplate2 = new RestTemplate();
final UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(host+initiatePaymentMenuhostpostfix);
Map paymentOrder = new HashMap();
paymentOrder.put("paymentorder", initiatePaymentMenuRequestBody());
final HttpEntity entity = new HttpEntity(paymentOrder,getHeadders());
LOG.info("initiatePaymentMenu===========> "+entity.getBody());
ResponseEntity<String> payExInitiatePaymentMenuResponse = restTemplate2.postForEntity(builder.build().encode().toUri(),entity,String.class);
LOG.info("initiatePaymentMenu" +payExInitiatePaymentMenuResponse.getStatusCode());
String returnString = payExInitiatePaymentMenuResponse.getStatusCode().toString();
return returnString;
}
Is I am doing the correct way? I am not getting the response and giving me 400 error. Is entity.getBody() prints the exact JSON? can I use it in postman to check the response?
Thanks in advance.

Solved. The web service is not accepting 2 different URLs in hostUrls field. It was a bug in the web service provider itself.

Related

Call Paginated Spring rest api from another spring project

I build one API which is paginated, its output looks like this:
{
"content": [
{JSON1},
{JSON2},
...
{JSON20}
],
"pageable": {
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"offset": 0,
"pageSize": 20,
"pageNumber": 0,
"unpaged": false,
"paged": true
},
"totalPages": 2,
"totalElements": 32,
"last": false,
"size": 20,
"number": 0,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"numberOfElements": 20,
"first": true,
"empty": false
}
So for this call, I have two pages and one each page we have 20 JSON entity is coming.
I wanted to call this same endpoint from the rest template.
Before pagination I used to call the same endpoint like this:
MyEntity[] responseEntity;
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", MediaType.APPLICATION_JSON_VALUE);
// request entity is created with request headers
HttpEntity<MyEntity> requestEntity = new HttpEntity<>(requestHeaders);
Map<String, String> params = new HashMap<>();
params.put("feild1", val1);
params.put("feild2", val2);
responseEntity = restTemplate.getForObject(ApiEndpoint,MyEntity[].class,params);
As the endpoint was returning in the format of Array of MyEntity, above code as good enough. Now I have paginated rest endpoint.
How should I call the paginated endpoint and get the Array of MyEntity data again?
So far I have tried calling with: which is not working for me.
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(ApiEndpoint);
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.queryParam(entry.getKey(), entry.getValue());
}
ResponseEntity<MyEntity[]> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, requestEntity, MyEntity[].class);
Let me know if another way you have can be implemented here. Thanks for your help in advance.
What i did is, created the new class RestPageImpl
#JsonIgnoreProperties(ignoreUnknown = true)
public class RestPageImpl<ConfigurationTable> extends PageImpl<ConfigurationTable> {
private static final long serialVersionUID = -1423116752405536063L;
#JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public RestPageImpl(
#JsonProperty("content") List<ConfigurationTable> content,
#JsonProperty("number") int number, #JsonProperty("size") int size,
#JsonProperty("totalElements") Long totalElements, #JsonProperty("pageable") JsonNode pageable,
#JsonProperty("last") boolean last, #JsonProperty("totalPages") int totalPages,
#JsonProperty("sort") JsonNode sort, #JsonProperty("first") boolean first,
#JsonProperty("numberOfElements") int numberOfElements) {
super(content, PageRequest.of(number, size), totalElements);
}
public RestPageImpl(List<ConfigurationTable> content, Pageable pageable,
long total) {
super(content, pageable, total);
}
public RestPageImpl(List<ConfigurationTable> content) {
super(content);
}
public RestPageImpl() {
super(new ArrayList<>());
}
}
And on the controller side updated my code to:
MyEntity[] responseEntity =null;
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Accept", MediaType.APPLICATION_JSON_VALUE);
// request entity is created with request headers
HttpEntity<MyEntity> requestEntity = new HttpEntity<>(requestHeaders);
Map<String, String> params = new HashMap<>();
params.put("feild1", val1);
params.put("feild2", val2);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(ApiEndpoint);
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.queryParam(entry.getKey(), entry.getValue());
}
ParameterizedTypeReference<RestPageImpl<MyEntity>> type = new ParameterizedTypeReference<RestPageImpl<MyEntity>>() {
};
responseEntity = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, requestEntity, type);
And everything works fine now.

Rx Observable onErrorReturnItem

I have following code
public Observable<Map<Integer, String>> getMultipleCitiesName(List<Integer> cityIds) {
Observable<Map<Integer, String>> observable = Observable.create(s -> {
try {
System.out.println("getMultipleCitiesName ==="+Thread.currentThread().getName());
List<String> cityIdsString = new ArrayList<>();
for (Integer cityId : cityIds) {
cityIdsString.add(cityId.toString());
}
MultiValueMap<String, String> formParams = new LinkedMultiValueMap<>();
formParams.put("cityIds[]", cityIdsString);
// Call the Location Client to call the API
Response<Map<Integer, String>> response = locationClient.getMultipleCitiesName(formParams);
s.onNext(response.getData());
} catch (Exception e) {
System.out.println("Inside Exception CITY NEW");
s.onError(e);
}
s.onComplete();
});
observable.onErrorReturnItem(new HashMap<>());
return observable;
}
Another stateObs.. same code
then
Observable<Map<Integer, String>> cityNamesObser = locationMediator.getMultipleCitiesName(cityIds);
Observable<Map<Integer, String>> stateNamesObs = locationMediator.getMultipleStatesName(stateIds);
Observable<Map<String, Map<Integer, String>>> zip = Observable.zip(
cityNamesObser,
stateNamesObs,
(cityNamesMap, stateNamesMap) -> {
System.out.println("Zipiing in Thread==="+Thread.currentThread().getName());
Map<String, Map<Integer, String>> result = new HashMap<>();
result.put("cityNames", cityNamesMap);
result.put("stateNames", stateNamesMap);
return result;
});
zip.blockingSubscribe(r -> {
System.out.println("Zip Subscribe in Thread==="+Thread.currentThread().getName());
System.out.println(r);
}, e->{
System.out.println("On Error zip");
});
}
Now the issue, observable.onErrorReturnItem is not working. Not working meaning it is throwing errror instead of returing blank hashmap
But If I change my code to
Observable<Map<Integer, String>> cityNamesObser = locationMediator.getMultipleCitiesName(cityIds).onErrroReturnItem(Blank Map);
Observable<Map<Integer, String>> stateNamesObs = locationMediator.getMultipleStatesName(stateIds).onErrroReturnItem(Blank Map);
Then it is working fine, meaning zip is returing blank hashmap with two keys cityNames and stateNames
Why is that? And do I make ny code work?
Ideally what I want to do is to return blank hashMap if any of my cityObs / stateObs gets failed. For that I want to trigger onError in case of Exception and attached onErrorReturnItem to Observable.

How to pass user context object to the response callback of async Jetty HTTP client?

When sending notifications to single recipients over Google Firebase Cloud Messaging, sometimes a response comes back (200 + error:MissingRegistration, 200 + error:InvalidRegistration, 200 + error:NotRegistered), which requires deleting the token of that recipient (because she for example reinstalled the Android app and the token has changed).
My question is:
How to pass that string (the FCM token) back to the response callback of the non-blocking Jetty HTTP client?
Currently my workaround is to add a custom HTTP header to my request:
X-token: APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...
and then I retrieve it in the response callback. But this is a hack, because FCM does not specify such a header and also I need to pass more custom data (the internal user id in my app) back.
Here is my current source code with the custom HTTP header, how to change it please?
private static final String FCM_URL = "https://fcm.googleapis.com/fcm/send";
private static final String FCM_KEY = "key=REPLACE_BY_YOUR_KEY";
private static final String FCM_RESULTS = "results";
private static final String FCM_ERROR = "error";
private static final String FCM_NOT_REGISTERED = "NotRegistered";
private static final String FCM_MISSING_REGISTRATION = "MissingRegistration";
private static final String FCM_INVALID_REGISTRATION = "InvalidRegistration";
private static final String FCM_X_TOKEN = "X-token";
private static final String TOKEN = "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...";
private static final Map<String, Object> REQUEST = new HashMap<>();
private static final Map<String, Object> NOTIFICATION = new HashMap<>();
private static final Map<String, Object> DATA = new HashMap<>();
static {
REQUEST.put("to", TOKEN);
REQUEST.put("notification", NOTIFICATION);
REQUEST.put("data", DATA);
NOTIFICATION.put("body", "great match!");
NOTIFICATION.put("title", "Portugal vs. Denmark");
NOTIFICATION.put("icon", "myicon");
DATA.put("Nick", "Mario");
DATA.put("Room", "PortugalVSDenmark");
}
private static final SslContextFactory sFactory = new SslContextFactory();
private static final HttpClient sHttpClient = new HttpClient(sFactory);
private static final BufferingResponseListener sFcmListener = new BufferingResponseListener() {
#Override
public void onComplete(Result result) {
if (!result.isSucceeded()) {
System.err.println(result.getFailure());
return;
}
String body = getContentAsString(StandardCharsets.UTF_8);
try {
Map<String, Object> resp = (Map<String, Object>) JSON.parse(body);
Object[] results = (Object[]) resp.get(FCM_RESULTS);
Map map = (Map) results[0];
String error = (String) map.get(FCM_ERROR);
System.out.printf("error: %s\n", error);
if (FCM_NOT_REGISTERED.equals(error) ||
FCM_MISSING_REGISTRATION.equals(error) ||
FCM_INVALID_REGISTRATION.equals(error)) {
String token = result.getRequest().getHeaders().get(FCM_X_TOKEN);
System.out.printf("TODO delete invalid FCM token from the database: %s\n", token);
}
} catch (Exception ex) {
System.err.println(ex);
}
}
};
public static void main(String[] args) throws Exception {
sHttpClient.start();
sHttpClient.POST(FCM_URL)
.header(HttpHeader.AUTHORIZATION, FCM_KEY)
.header(HttpHeader.CONTENT_TYPE, "application/json")
.header(FCM_X_TOKEN, TOKEN) // Workaround, how to improve?
.content(new StringContentProvider(JSON.toString(REQUEST)))
.send(sFcmListener);
}
You want to set the token as a request attribute and the retrieve it back:
httpClient.POST(url)
.attribute(key, token)
...
.send(new BufferingResponseListener() {
#Override
public void onComplete(Result result) {
Object token = result.getRequest().getAttribute(key);
...
}
});

How to pass the request body with multi level data using rest-assured

Trying to send the request body with multi level data using rest-assured in the following way.
Request body:
{
"phoneNumber":1217071016,
"details":
[
{
"id":"123",
"name":"New",
"email":"hello#gmail.com"
},
{
"id":"234",
"name":"next",
"email":"next#gmail.com"
}
]
}
#Test public void generateToken() {
Map<String,String> userDetails = new HashMap<>();
userDetails.put("phoneNumber", "1217071016");
userDetails.put("details.Id", "241342");
userDetails.put("details.name", "New Name");
userDetails.put("details.email", "eclipse#test.com");
Response response = given()
.contentType("application/json")
.queryParam("access_token", "LL6rX8LRP7")
.body(userDetails)
.post("http://site/rest/try/update");
}
When sent in the above way, getting the bad request.
How to pass this kind of data in the above code
You need not a Map<String, String> but a Map<String, Object>:
Map<String, Object> userDetails = new HashMap<>();
Map<String, Object> details = new HashMap<>();
details.put("id", "241342");
details.put("name", "New Name");
details.put("email", "eclipse#test.com");
userDetails.put("phoneNumber", "1217071016");
userDetails.put("details", Arrays.asList(details, details));

HTTP Status 500 - org.springframework.web.client.HttpClientErrorException: 404 /

I am using RestTemplate, but when i call postFor function i get following exception, Below are the code for showing detail:
Controller
#Controller
#RequestMapping("/data")
public class DataController {
#RequestMapping(value = "/{id}", method = RequestMethod.POST)
public ResponseEntity<ManagementResource> postData(#PathVariable("id") String id,#RequestBody Data1 data) {
RSResponse<Data1> response = new RSResponse<Data1>();
response.setStatus(RSResponse.Status.SUCCESS);
response.setData(data);
return new ResponseEntity<ManagementResource>(HttpStatus.CREATED);
}
}
client code:
RestTemplate rt = new RestTemplate();
Data1 d = new Data1();
d.setEmp_id(1);
d.setEmp_name("abc");
d.setEmp_salary(10000);
Map<String, String> vars = new HashMap<String, String>();
vars.put("id", "JS01");
String url = "http://localhost:8090/JSFFaceletsTutorial/data/{id}";
ResponseEntity<Data1> response = rt.postForEntity(url,d,Data1.class,vars);
Data1 data = response.getBody();
please tell if anyone knows it.
Thanks
Does your service need headers? If so, you can pass like this,
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Accept", "application/json");
HttpEntity<Data1> request = new HttpEntity<Data1>(d, headers);
ResponseEntity<Data1> response = rt.postForEntity(url,request,Data1.class,vars);
Data1 data = response.getBody();