I am trying to make a POST request using the Micronaut framework with Java. I have created a 'client' class that is called and makes the request. Here is the code:
#Singleton
public class ApiClient {
private final HttpClient httpClient;
private final URI uri;
public ApiClient(#Client(URL) HttpClient httpClient) {
this.httpClient = httpClient;
uri = UriBuilder.of(API_URL).build();
}
Mono<List<ApiResponse>> fetchResponse() {
HttpRequest<?> request = HttpRequest.POST(uri, BODY)
.header("Authorization", API_KEY);
return Mono.from(httpClient.retrieve(request, Argument.listOf(ApiResponse.class)));
}
}
My problem is that I have no idea what the response from API is. As far as I can tell, the call is made. But because the data returns in a Flux object, I can't interrogate the object to find the response. My suspicion is that the POJO I'm trying to store the response in isn't working. I can't tell if this is the case though.
You need to subscribe to the publisher to actually make the request and get a response. There are several subscribe methods depending on what you want to do
Related
I'm using the Java SDK to start a voice call using something similar to
Call.creator(to, from, callbackAddress)
I provide a URL (callbackAddress) that will receive the callback once the call is connected. Is there some way to configure this callback to be in JSON instead of "application/x-www-form-urlencoded; charset=UTF-8"?
The reason why I'm trying to do that is because I'm using Spring and ultimately I'm trying to receive the request parameters already in a deserialized Pojo in my RestController (parameter body in my example below), which is standard in SpringMVC. This is much easier to do using jackson, which requires a JSON request body
As a secondary question, is there a class in the Twilio SDK that encapsulates all the parameters in a request already or I would have to create such class?
Here is a dummy rest controller to illustrate what I'm trying to do. Note that the logic there with the "out of city" error is just a silly demo to show why I need to access the request parameters. All the samples I found about callbacks always ignored the request parameters and returned a static TwiML
#RestController
#RequestMapping(value = "/twilio", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class TwilioCallbackController {
#PostMapping
public String handleCallback(RequestBody body /*this arg should have all request params*/) {
log.info("received callback for callId {}", body.getCallSid())
if (!body.toCity().equals("my-city")) {
throw new Exception("outside of city");
}
return createTwiML(body);
}
}
Twilio developer evangelist here.
There is no way to have Twilio send you the webhook in JSON format, it will be sent as form encoded parameters. However, there shouldn't be an issue having Spring parse them.
As this answer suggests, you can create a class that will parse the parameters into it by creating a class with getters and setters for each of the parameters.
So, for example, you could create the following class:
public class TwilioWebhook {
private String CallSid;
private String From;
public String getCallSid() {
return CallSid;
}
public void setText(String CallSid) {
this.CallSid = CallSid;
}
}
Which you could then use to parse the CallSid from the incoming webhook parameters like:
#RestController
#RequestMapping(value = "/twilio", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public class TwilioCallbackController {
#PostMapping
public String handleCallback(TwilioWebhook request) {
log.info("received callback for callId {}", request.getCallSid())
// rest of the controller.
}
}
You can parse all the parameters by adding to the TwilioWebhook class. You can see all the parameters that Twilio will send in the Twilio voice request documentation. There isn't a class in the Twilio SDK that does this for you though.
Depends on request body content I need to redirect http requests to URL_1 or URL_2.
I started controller implementation:
#RestController
public class RouteController {
#Autowired
private RestTemplate restTemplate;
#RequestMapping(value = "/**")
public HttpServletResponse route(HttpServletRequest request) {
String body = IOUtils.toString(request.getReader());
if(isFirstServer(body)) {
//send request to URL_1 and get response
} else {
//send request to URL_2 and get response
}
}
}
Request might be GET or POST ot PUT or PATCH etc.
Could you help me to write that code?
I've asked a somehow similar question a while ago. Plea see Server side redirect for REST call for more context.
The best way (to my current understanding) you could achieve this is by manually invoking the desired endpoints from your initial endpoint.
#RestController
public class RouteController {
#Value("${firstUrl}")
private String firstUrl;
#Value("${secondUrl}")
private String secondUrl;
#Autowired
private RestTemplate restTemplate;
#RequestMapping(value = "/**")
public void route(HttpServletRequest request) {
String body = IOUtils.toString(request.getReader());
if(isFirstServer(body)) {
restTemplate.exchange(firstUrl,
getHttpMethod(request),
getHttpEntity(request),
getResponseClass(request),
getParams(params));
} else {
restTemplate.exchange(secondUrl,
getHttpMethod(request),
getHttpEntity(request),
getResponseClass(request),
getParams(params))
}
}
}
Example implementation for getHttpMethod:
public HttpMethod getHttpMethod(HttpServletRequest request) {
return HttpMethod.valueOf(request.getMethod());
}
Similar implementations for getHttpEntity, getResponseClass and getParams. They are used for converting the data from the HttpServletRequest request to the types required by the exchange method.
There seem to be a lot of better ways of doing this for a Spring MVC app, but I guess that it does not apply to your context.
Another way you could achieve this would be defining your own REST client and adding the routing logic there.
I'm doing cucumber bdd tests i have a class [MyClient] that wraps restassured methods and I have multiple classes that calls [MyClient].
I can do methods like put, post etc. just fine but I am wondering whether there is a way for me to get the actual request fields (header, body...) sent after doing the request.
I also dont have any problems getting and parsing the response but I'm unable to get the request sent.
Considering the following, I can call the sendPostRequest() that will store the RequestSpecification instance to a field called request and I can fetch it anytime by calling the getter. However, I cannot take the individual fields from the RequestSpecification object. From the debugger, I can see the fields just fine so I was thinking there has to be some clean way for me to get it.
I've already tried log() but it doesnt seem to give me what I need.
Any help is appreciated!!
CALLING CLASS:
public class MyInterfaceSteps() {
private myClient = new MyClient();
public sendPostRequest(){
myClient.post(someHeaders, someBody, someUrl);
}
}
CLIENT CLASS:
public class MyClient() {
private RequestSpecification request;
private Response response;
public getRequest() {
return request;
}
public getResponse() {
return response;
}
public Response post(Map<String, String> headers, String body, String url) {
request = given().headers(headers).contentType(ContentType.JSON).body(body);
response = request.post(url);
}
}
You create a filter (https://github.com/rest-assured/rest-assured/wiki/Usage#filters) which gives you access to FilterableRequestSpecification (http://static.javadoc.io/io.rest-assured/rest-assured/3.0.3/io/restassured/specification/FilterableRequestSpecification.html) from which you can get (and modify) e.g. headers and body etc. The filter could store these values to a datastructure of your choice.
I am trying to learn about Retrofit since it seems to take care of a lot of the issues I am currently having with JSON requests and handling.
first and foremost, I understand that the methods we use are defined inside of interfaces, while making simple requests to obtain data it is quite simple to specify what is to be retrieved from the url as well as all the necessary endpoints based on the famous github example.
So if we are retrieving information form the github api, we would first create all the necessary pojo models and such and then define the interface as:
public interface GithubService {
#GET("users/{username}")
Observable<Github>getGithHubUser(#Path("username")String userName);
}
From that on the main activity we would have something like:
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://api.github.com/")
.build();
GithubService githubService = retrofit.create(GithubService.class);
Observable<Github> githubUser = githubService.getGithHubUser("usersName");
githubUser.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.map(user -> "Github Username: " + user.getName() + "\nUrl:" +user.getUrl() + "\nfollowing: "+ user.getHireable())
.subscribe(userInfo -> Log.d("Output", userInfo));
My question here would be how to send JSON information if the url requires something like this:
"data={\"process\":\"procesNumber\", \"phone\":\"123456\"}"
Basically, in order to get any response form the server I have been doing this using simple okhttp:
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(CREATE_MEDIA_TYPE, "data={\"process\":\"procesNumber\", \"phone\":\"123456\"}");
String ALLWAYS_API = "http://something something bla bla";
Request request = new Request.Builder()
.url("https://blablabla")
.post(body)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
... etc etc etc
}
To my understanding, even I need to create a pojo class that represents the data that needs to be sent to retrofit, something along the lines of:
public class DataRequest {
final String proces;
final String phone;
DataRequest(String process, String phone) {
this.process = process;
this.phone = phone;
}
}
Which would comply to the information being sent to the request, but how would I actually parse that to the interface implementation?
interface DataService {
#Post(not a clue what to place here)
DataRequest postJson(#Body how?)
}
And how would I actually add that to the retrofit builder? The examples that I am using come from different forums on the web as well as other questions asked by other users, this one in particular helped a lot in understanding a couple of things: How to POST raw whole JSON in the body of a Retrofit request? but I still don't understand where everything goes and some of the other questions and examples are far too complex for what I need to do.
Ok, so in order to leave an answer here for anyone trying to do this. By default, retrofit comes with many utilities which handle the passing of data as JSON, but in this case what I am passing is a string that looks like json inside of a tag called data......I know..
But in order to answer this for the people facing similar issues, in order to pass in the string we need to import a scalar convertor much in the same way that we need to import a gson converter to work with our retrofit services:
compile 'com.squareup.retrofit2:converter-scalars:2.0.2'
After that, our service can be handled as:
public interface CreateService {
#Headers({ "Content-Type: application/x-www-form-urlencoded;charset=UTF-8"})
#POST("your/post/path/goes/here")
Call<String> getStringScalar(#Body String body);
}
I write my service generators in a separate file, in this case, the whole thing can be used in this way:
public class ServiceGeneratorWithScalarConvertor {
private static final String API_BASE_URL = "your/base/url/goes/here";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
// basically, this code is the same as the one from before with the added instance of creating and making use of the scalar converter factory.....scratch that i took it off
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
builder.client(httpClient.build());
Retrofit retrofit = builder.build();
return retrofit.create(serviceClass);
}
}
From there, we can access the results with this particular method(i am using this method inside my main activity:
public void retroFitCreateAPIExample() {
CreateService service = ServiceGeneratorWithScalarConvertor.createService(CreateService.class);
String body = "data={\"process\":\"process1\",\"phone\":\"12345\"}";
Call<String> call = service.getStringScalar(body);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful()){
Log.d("Response Body>>>>>", response.body());
createR = new Gson().fromJson(response.body().toString(), CreateModels.class);
Log.d("CREATED RESPONSE",createR.getCreate().getStops().get(0).getCity());
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
}
});
}
The instance is this passed to the service generator that uses scalar convertors, the body of the post request is saved as a simple string(as it was specified in the interface) and we can do with the response whatever we want.
I am using Apache HttpClient 4.5's Fluent API, the following way:
CloseableHttpClient client = HttpClientBuilder.create().build();
Executor executor = Executor.newInstance(client);
Response resp = executor.execute(Request.Get(url));
Unfortunately, I can't find a proper way of getting redirect locations (the RedirectLocation class).
They are normally stored in a HttpContext object; but when using the Fluent API, its instance is created locally in Executor.execute(...) and never exposed:
public Response execute(final Request request) {
final HttpClientContext localContext = HttpClientContext.create();
/* ... */
return new Response(request.internalExecute(this.httpclient, localContext));
}
I've tried to override Executor.execute(...) method by creating a decorator/proxy class; by creating a child class; even by copy-pasting its source into my own package.
None of these solutions were feasible (for one, Executor invokes package-local methods of other classes).
The only workaround I've managed to find so far was to implement my own RedirectStrategy and pass it to HttpClient:
public class MyRedirectStrategy extends DefaultRedirectStrategy {
private HttpContext context;
public RedirectLocations getRedirectLocations() {
return (RedirectLocations) context.getAttribute(REDIRECT_LOCATIONS);
}
#Override
public URI getLocationURI(final HttpRequest request, final HttpResponse response, final HttpContext context) {
this.context = context; // to keep the HttpContext!
return super.getLocationURI(request, response, context);
}
}
/* ... */
RedirectStrategy stra = new MyRedirectStrategy();
CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(stra).build();
Executor executor = Executor.newInstance(client);
Response resp = executor.execute(Request.Get(url));
for (final String redirectedUri : stra.getRedirectLocations()) {
/* process redirectedUri's */
}
However, I don't think it is a proper solution. To my knowledge, RedirectStrategies were intended to be immutable, stateless classes, as they are passed to the HttpClient, which can be shared by multiple threads/connections.
In other words: logically, the HttpContext is not a property of a RedirectStrategy.
Any ideas?
Thanks!
You cannot. HC fluent API hides HttpContext instance way from the consumer. Consider using HttpClient APIs directly.