Making nested http requests java asynchronous - java

I am using play java for my project(java play ws API) and
private CompletionStage<String> getAuthToken() {
WSRequest request = ws.url(URL);
WSRequest complexRequest = request.setHeader("X-API-Key", X_API_KEY)
.setHeader(CONTENT_TYPE, CONTENT_TYPE_VALUE)
.setHeader(AUTHORIZATION, CLIENT_DETAILS_BASE64_ENCODE);
CompletionStage<WSResponse> responsePromise = complexRequest.post(GRANT_TYPE + "="
+ PASSWORD + "&" + USERNAME + "=" + USERNAME + "&" + PASSWORD + "=" + PASSWORD);
return responsePromise.thenApply(response-> getAuthToken2().toString());
}
private CompletionStage<String> getAuthToken2() {
WSRequest request = ws.url(URL);
WSRequest complexRequest = request.setHeader("X-API-Key", X_API_KEY)
.setHeader(CONTENT_TYPE, CONTENT_TYPE_VALUE)
.setHeader(AUTHORIZATION, CLIENT_DETAILS_BASE64_ENCODE);
CompletionStage<WSResponse> responsePromise = complexRequest.post(GRANT_TYPE + "="
+ PASSWORD + "&" + USERNAME + "=" + USERNAME + "&" + PASSWORD + "=" + PASSWORD);
return responsePromise.thenApply(response-> addIdentity(response.asJson().findValue("access_token").toString()).toString());
}
What is the mistake I am making? How do I make nested requests one after the other one?
I get
java.util.concurrent.CompletableFuture#75c6e852[Not completed]
as the response to my client

You have to use thenCompose to chain multiple http requests. Here is a working sample: for three sites, we will fetch their page and add the status code to a JSON object. At the end, we return that object.
public CompletionStage<Result> getSites() {
ObjectNode hosts = Json.newObject();
return ws.url("https://www.facebook.com").get()
.thenCompose(res -> {
hosts.put("facebook", res.getStatus());
return ws.url("https://www.google.com").get();
})
.thenCompose(res -> {
hosts.put("google", res.getStatus());
return ws.url("https://www.twitter.com").get();
})
.thenApply(res -> {
hosts.put("twitter", res.getStatus());
return ok(hosts);
});
}

Related

Why -from Java- JSON returns this error? Clearly is in the JSON deserialization, but I cannot find exactly where it occurs

Situation:
[![from Postman, JSON returns the data correctly][1]][1]
[1]: https://i.stack.imgur.com/4Kk0J.png
Server side:
Enables the reading of the request body for all routes under /api/articulos.
Router router = Router.router(vertx);
router.route("/api/articulos*").handler(BodyHandler.create());
router.get("/api/articulos/:cantcomp1/:cantcomp2/:tipoprod/:prodpadre").handler(bizArticulo::getOneReadingBarcode);
Business
private static final String SELECT_CBA = "select art.leyenda, $1 :: numeric as cantidad, uni.abreviatura, "
+ "round(((art.precio_costo * (art.utilidad_fraccionado/100)) + art.precio_costo) * ($2),2) as totpagar "
+ "FROM public.articulos art join public.unidades uni on uni.idunidad = art.idunidad "
+ "WHERE (substring(art.codigobarra,1,2) = ($3) and substring(art.codigobarra,3,6) = ($4))";
public void getOneReadingBarcode(RoutingContext routingContext) {
Double cantComprada1 = Double.parseDouble(routingContext.request().getParam("cantcomp1"));
Double cantComprada2 = Double.parseDouble(routingContext.request().getParam("cantcomp2"));
String tipoProducto = routingContext.request().getParam("tipoprod");
String productoPadre = routingContext.request().getParam("prodpadre");
HttpServerResponse response = routingContext.response();
pgClient
.preparedQuery(SELECT_CBA)
.execute(Tuple.of(cantComprada1, cantComprada2, tipoProducto, productoPadre), ar -> {
if (ar.succeeded()) {
RowSet<Row> rows = ar.result(); // return always ONE ARTICLE
List<Articulo> articulos = new ArrayList<>();
rows.forEach(row -> {
articulos.add(fromBarCode(row));
});
response.putHeader("content-type", "application/json; charset=utf-8")
.setStatusCode(200)
.end(Json.encodePrettily(articulos));
} else {
System.out.println("Failure: " + ar.cause().getMessage());
response.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily(ar.cause().getMessage()));
}
});
}
private static Articulo fromBarCode(Row row) {
String leyenda = row.getString("leyenda");
BigDecimal cantComprada = row.getBigDecimal("cantidad");
String abreviatura = row.getString("abreviatura");
BigDecimal total_a_pagar = row.getBigDecimal("totpagar");
Articulo articulo = new Articulo();
articulo.setLeyenda(leyenda);
articulo.setCant_comprada(cantComprada);
articulo.setAbreviatura(abreviatura);
articulo.setTot_a_pagar(total_a_pagar);
return articulo;
}
Client-side
private void validarArticulo() {
switch (txtCodigoBarra.getText().substring(0,2)) {
case "20":
Integer d = Integer.parseInt(txtCodigoBarra.getText().substring(8, 12));
Double decimal = d * 0.001; // convert to kilos
System.out.println(
String.format("%.3f", decimal) + " | " +
String.format("%.3f", decimal) + " | " +
txtCodigoBarra.getText().substring(0, 2) + " | " +
txtCodigoBarra.getText().substring(2, 8)
);
PosAccess
.getCodigoBarra(
decimal,
decimal,
txtCodigoBarra.getText().substring(0, 2),
txtCodigoBarra.getText().substring(2, 8));
case "77":
}
public static ObservableList<Articulo> getCodigoBarra(Double cantComp1, Double cantComp2, String tipoProducto, String productoPadre) {
ObservableList<Articulo> itemsArticulo = FXCollections.observableArrayList();
WebClient client = WebClient.create(Vertx.vertx());
client
.get(PORT, HOST, "/api/conceptos/" + cantComp1 + "/" + cantComp2 + "/" + tipoProducto + "/" + productoPadre)
// .get(PORT, HOST, "/api/conceptos/")
// .setQueryParam("cantcomp1", cantComp1)
// .addQueryParam("cantcomp2", cantComp2)
// .addQueryParam("tipoproducto", tipoProducto)
// .addQueryParam("productopadre", productoPadre)
.send(ar -> {
if (ar.succeeded()) {
HttpResponse<Buffer> response = ar.result();
response.bodyAsJsonArray().forEach(articulo -> {
JsonObject jo = (JsonObject) articulo;
itemsArticulo.add(new Articulo(jo.getString("leyenda"), jo.getDouble("cant_comprada"), jo.getString("abreviatura"), jo.getDouble("tot_a_pagar")));
});
System.out.println("Received response with status code " + response.statusCode());
System.out.println(response.bodyAsJsonArray());
} else {
System.out.println("Something went wrong " + ar.cause().getMessage());
}
});
return itemsArticulo;
}
Ok, that's the code. When scan the barcode I get this error
0,750 | 0,750 | 20 | 021162
oct. 11, 2020 6:33:18 A. M. io.vertx.core.impl.ContextImpl
SEVERE: Unhandled exception
io.vertx.core.json.DecodeException: Failed to decode:Unexpected character ('<' (code 60)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 2]
at io.vertx.core.json.jackson.JacksonCodec.fromParser(JacksonCodec.java:100)
at io.vertx.core.json.jackson.JacksonCodec.fromBuffer(JacksonCodec.java:67)
at io.vertx.ext.web.codec.impl.BodyCodecImpl.lambda$static$2(BodyCodecImpl.java:51)
at io.vertx.ext.web.client.impl.HttpResponseImpl.bodyAsJsonArray(HttpResponseImpl.java:116)
at consumer.PosAccess.lambda$0(PosAccess.java:45)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 2]
... 22 more
Anyboy can help me?
TIA
Ernesto
You are calling the wrong endpoint (i.e. /api/conceptos/ instead of /api/articulos).
In the screenshot provided in the post, which illustrates a correct response, you are showing a response for url
192.168.0.15:8092/api/articulos/0.75/0.75/20/021162
but in the code you have
client.get(PORT, HOST, "/api/conceptos/" + cantComp1 + "/" + cantComp2 + "/" + tipoProducto + "/" + productoPadre)
According to my experiences, this error message:
io.vertx.core.json.DecodeException: Failed to decode:Unexpected character ('<'
usualy happens when you try to deserialize an api response into a json, but indeed the response is something like:
<html><body><h1>Resource not found</h1></body></html>
or
<html><body><h1>Internal server error</h1></body></html>
and the parsing fails at the first char <
For your case, this happens at response.bodyAsJsonArray() probably.
please make a debug output for the url what you are calling:
String url = "/api/conceptos/" + cantComp1 + "/" + cantComp2 + "/" + tipoProducto + "/" + productoPadre;

Webview Send Post Json

I have String Json:
String data = "param:"+"{\"dataFile\": \n" +
"{\"user\": \"asdasdasd\", \n" +
"\"pwd\":\"vasdadsda\", \"email\": \"vasdasdasd#gg.com\" \n" +
"}\n" +
"}";
Then try to send post to API with webview JSON like this:
myWebView.postUrl("url.com", data.getBytes());
from API the json process with "param" key then get the value, but the json get from API is null, any clue ?
I post my data like this. You may also try with this.
String postData = null;
try {
postData = "email=" + URLEncoder.encode(MyApp.getSharedPrefString(StaticData.EMAIL), "UTF-8") + "&password=" + URLEncoder.encode(MyApp.getSharedPrefString(StaticData.PASSWORD), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
webview.postUrl("url.com",postData.getBytes());

400 bad request without error message - Twitter API

Hey guys!
I'm currently trying to create an app that uses the Twitter API to get timelines of users. I'm currently stuck at a specific point! My user has already logged in and I've already received the access token and the token secret. I'm now trying to send a get request to the Twitter server.
My problem is that I'm always getting a 400 bad request error code WITHOUT any kind of message.
I'm using Volley to send the requests - Heres the code
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Response Time: " + error.getNetworkTimeMs() + " ms");
Log.e(TAG, "Code: " + error.networkResponse.statusCode);
Log.e(TAG, "Data: " + new String(error.networkResponse.data));
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
Long tsLong = System.currentTimeMillis() / 1000;
//I receive all the difference parts
String consumerKey = context.getString(R.string.twitter_consumer_key);
String nonce = GenerationHelper.generateNonce();
String signature_method = "HMAC-SHA1";
String timestamp = tsLong.toString();
String token = sTwitterToken;
String version = "1.0";
// I use this list to pass the parameters to the function
// generating the signature
List<String> param= new ArrayList<>();
param.add("screen_name=" + username);
param.add("count=" + count);
param.add("oauth_token" + sTwitterToken);
param.add("oauth_consumer_key=" + consumerKey);
param.add("oauth_nonce=" + nonce);
param.add("oauth_signature_method=" + signature_method);
param.add("oauth_timestamp=" + timestamp);
param.add("oauth_version=" + version);
String signature = GenerationHelper.generateSignature(context, param, "POST", "https://api.twitter.com/1.1/statuses/user_timeline.json");
// I create the header String
StringBuilder paramBuilder = new StringBuilder();
paramBuilder.append("oauth_consumer_key=\"" + consumerKey + "\", ");
paramBuilder.append("oauth_nonce=\"" + nonce + "\", ");
paramBuilder.append("oauth_signature=\"" + signature + "\", ");
paramBuilder.append("oauth_signature_method=\"" + "HMAC-SHA1" + "\", ");
paramBuilder.append("oauth_timestamp=\"" + timestamp + "\", ");
paramBuilder.append("oauth_token=\"" + sTwitterToken + "\", ");
paramBuilder.append("oauth_version=\"" + "1.0" + "\"");
String credentialString = paramBuilder.toString();
Log.d(TAG, credentialString);
params.put("Authorization", "OAuth " + credentialString);
return params;
}
};
My current response is
Code: 400
Data:
If I remove the line adding the authorization data I get the response
Code: 400
Data: {"errors":[{"code":215,"message":"Bad Authentication data."}]}
I'm pretty sure that I don't get rate limited because I'm just sending about 10 requests per 15 minutes.
Does anybody have any idea why I'm having this problem?

how to send request payload in json data using post method

String pay= "["
+ "{"
+ "\"internalAssessmentResponseId\" : \"Mer\\/ccclsv__AC1B752E-D079-4BA9-AA4F-46E1F8DDC11F__3048\","
+ "\"responses\":["
+ "{"
+ "\"assessmentCreatedDate\":\"2016-11-25T11:35:54\","
+ "\"responseData\":[],"
+ "\"assessmentId\":\"943\","
+ "}"
+ "],"
+ "\"addtionalInformation\":[],"
+ "\"emailId\":\"lucky#me.com\","
+ "\"salesTeam\" :\"\","
+ "\"demographic\": {"
+ "},"
+ "\"repId\":\"AJMA-OG9OMQ\","
+ "\"assesseeId\":\"AGHA-2D0FVL\","
+ "\"assesseeType\":\"CONTACT\","
+ "\"typeOfResponse\":\"iPad\","
+ "\"userTimeZone\":\"a\""
+ "}"
+ "]";
HttpClient httpclient = new HttpClient();
PostMethod post = new PostMethod("http://signature");
post.setRequestEntity(new StringRequestEntity(pay, "application/json", null));
httpclient.executeMethod(post);
String jsonResponse = post.getResponseBodyAsString();
jsonInsertRes = jsonResponse;
System.out.println("Response in create==>"+jsonResponse);
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch
(IOException e)
{
e.printStackTrace();
}
return jsonString.toString();
}
I am getting wrong response like this
Can not construct instance of org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput, problem: abstract types can only be instantiated with additional type information
at [Source: org.apache.catalina.connector.CoyoteInputStream#11ff00b3; line: 1, column: 1]
You can try sending JSON string as a string form parameter
and then on server read the JSON string value and convert the string to a Java Object(say object of Message.java as for example).
Message msgFromJSON = new ObjectMapper().readValue(JSONString, Message.class);
I have tried few times and it worked fine.

POST data to other URI with URL change in REST (POST and Redirect)

I need to POST data and at the same time redirect to that URL in REST environment. I can do this for normal strings, but the requirement is to POST specific Object.
The way I do it for normal string is -
public Response homePage(#FormParam("username") String username,
#FormParam("passwordhash") String password) {
return Response.ok(PreparePOSTForm(username)).build();
}
private static String PreparePOSTForm(String username)
{
//Set a name for the form
String formID = "PostForm";
String url = "home";
//Build the form using the specified data to be posted.
StringBuilder strForm = new StringBuilder();
strForm.append("<form id=\"" + formID + "\" name=\"" +
formID + "\" action=\"" + url +
"\" method=\"POST\">");
strForm.append("<input type=\"hidden\" name=\"" + "username" +
"\" value=\"" + username + "\">");
strForm.append("</form>");
//Build the JavaScript which will do the Posting operation.
StringBuilder strScript = new StringBuilder();
strScript.append("<script language=\"javascript\">");
strScript.append("var v" + formID + " = document." +
formID + ";");
strScript.append("v" + formID + ".submit();");
strScript.append("</script>");
//Return the form and the script concatenated.
//(The order is important, Form then JavaScript)
return strForm.toString() + strScript.toString();
}
But this method is not sending Objects. I need a work around to send complex Objects. Please help me with this issue.
Thanks in advance.

Categories