Defining Retrofit2 interface - Method without Response body - java

I am defining the Call objects in a Retrofit2 interface, to consume an external Rest API.
For most of the calls, we have something similar to :
#POST("/api/v1/methodEndPoint")
public Call<MethodResponse> methodName(#Body MethodRequest methodRequest);
However, my question is: How should I define a method if there is no Response object (a POST call, with no response body, we just mind about the status). Retrofit throws an exception if I just write the following:
#POST("/api/v1/methodEndPoint")
public Call methodName(#Body MethodRequest methodRequest);
Thanks for your help, have a nice day!

For defining a method without any response in Retrofit 2, the return type of method should be Void
You can try like :
#POST("/api/v1/methodEndPoint")
Call <Void> methodName(#Body MethodRequest methodRequest);

Use ResponseBody. Basically, you can do it like this:
#POST("/api/v1/methodEndPoint")
public Call<ResponseBody> methodName(#Body MethodRequest methodRequest);
You will have access to onResponse and onFailure callbacks however there will be no data deserialisation attempt

Related

Get the query parameter passed to retrofit inside onResponse method inside callback

I have a requirement to use the query parameter that is passed inside retrofit query inside onResponse if it is successful. I can't use global variable as it will change before getting the response.
The onResponse method gives you the original call related to that response:
call!!.request()
the request contains the url related to that particular response, the headers and, if present, the body.
If you parse those data you can get the original parameters
call.request().url().queryParameter("id") this solved the problem

How to use retrofit without any pojo or data class or model class

I am working on an application where I want to use retrofit, but response from API is very large and can not be converted in any data class or POJO class, and also the response is dynamic it increase with user actions for backup, So I want to ask this a long time that is there any way where I can use retrofit without making response data class or POJO class otherwise I have to move back to basic Http way of using REST api's .
If anyone have achieved this or used before , please give some idea how to achieve this, would be a great help. Thanks in advance.
From retrofit docs:
[1] Retrofit is the class through which your API interfaces are turned into callable objects.
[2] Retrofit turns your HTTP API into a Java interface.
Sole purpose of Retrofit is to abstract your API calls as Java interfaces. IT was meant to be used with interfaces and POJOs, it is designed that way. If you don't want to use POJOs, you can use OkHttp which is actually used by Retrofit under the hood. Retrofit should only be used when you need an abstraction for your HTTP calls as Java objects.
You can always just send strings via the #Body annotation.
public interface YourService{
#POST("some/extension")
Call<Object> makeCall(#Body String body);
}
You can access the body of the response like this:
service.makeCall(yourCustomString).enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response) {
String content = response.body(); // this gives the response body as a string
}
#Override
public void onFailure(Throwable t) {...}
});
I still think using JSON-Converters is the way to go. You might just need a lot of nested classes inside of the wrapping response/request classes depending on the JSON structure. The size beeing different doesn't matter and can easly be created using lists and optional attributes. How big do your responses get? Moshi for example doesn't really have a size limit.

Intercepting an assignment in Java

I'm using REST-Assured library with TestNG for receiving the response in a Response object as below.
Response response;
#Test
public void someTest() {
RestAssured.baseURI = "some_valid_baseURI";
RestAssured.basePath = "some_valid_endpoint";
response = RestAssured.given().contentType(ContentType.JSON).when().get();
}
I have several test methods like the above-mentioned method in a test class. Is there any way to intercept the response assignment so that I can, somewhere else (e.g. in a method annotated by an #AfterMethod), know that the method being used to get the response is the GET method?
PS: I did not find any in-built way in the REST-Assured library to do this.
The answer in Is it possible to extract the method name from the response object? serves my purpose for this question. Sorry about the generic question line here though!

Override HttpMessageConverter for Spring RequestBody

I have the following code:
#RequestMapping(value="/mobile/device", method = RequestMethod.PUT)
public ResponseEntity<Void> flagDevice (#RequestBody List<MobileDeviceData> devicedataList, #RequestHeader(value="special_code") String specialCode) {
// Implementation details
}
Each instance of MobileDeviceData that gets created needs to have a param field filled in with the RequestHeader special_code.
How would I go about doing this so that it is fully populated by the time the flagDevice method body gets called?
Thanks in advance.
This is non trivial.
An HttpMessageConverter is already provided that deserializes the JSON, that's the MappingJackson2HttpMessageConverter. It has access to request headers. You could extend that class to also use the headers for deserialization (this is extremely difficult to do generically, as opposed to only for MobileDeviceData).
You could use Spring AOP, intercept the method, retrieve the arguments, cast to the appropriate types, and assign the value yourself.
The solution I would go for is the simplest: do it yourself in the handler method. Loop the the List and use a corresponding setter to set the specialCode for each MobileDeviceData.
Another option is to define your own HandlerMethodArgumentResolver specifically for List<MobileDeviceData> parameters that need to be constructed from header vales.

Consuming different input JSON format by same URL and same method in Spring RESTful service

I'm going to implement a RESTful webservice using Spring.
Let it be an ordinary PUT method, something like this:
#RequestMapping(method=RequestMethod.PUT, value="/foo")
public #ResponseBody void updateFoo(#RequestBody Foo foo) {
fooService.update(foo);
}
In such a case input JSON format (if it corresponds to Foo class) will be successfully converted to Foo instance with no extra efforts, or error will be issued in case of wrong format.
But I'd like to make the service able to consume two different types of formats using same method (e.g. PUT) and same URL (e.g. /foo).
So that it possibly looked like:
//PUT method #1
#RequestMapping(method=RequestMethod.PUT, value="/foo")
public #ResponseBody void updateFoo(#RequestBody Foo foo) {
fooService.update(foo);
}
//PUT method #2
#RequestMapping(method=RequestMethod.PUT, value="/foo")
public #ResponseBody void updateFoo(#RequestBody FooExtra fooExtra) {
fooService.update(fooExtra);
}
and Spring converter tried to convert input JSON not only in Foo but in FooExtra as well and invoked corresponding PUT method depending on input format.
In fact, I tried to implement it exactly as it described above but without success. Is it even possible? Maybe, I need some kind of "trick"?
What is the best (and the most proper) way to achieve such behavior? Of course, I could always make two different URLs but I'd like to know whether it is possible with the same one.
Your attempt didn't work simply because Spring tried to match your methods against the request, by looking at url and method type, which are in both cases the same. It does not work like overloading in Java; argument types do not differentiate your methods.
But there are good news. SpringMVC can also examine request headers and request parameters when trying to match your handler methods. Since what you want to pass is actually pure metadata -an alternative format type of the same information- it makes perfect sense to use a custom request header. It's very easy to add custom headers when using a rest api. See the following link for JAX-RS: Adding a custom header.
Now in your server side you should configure the handler methods as:
//PUT method #1
#RequestMapping(method=RequestMethod.PUT, value="/foo", headers="returnType=Foo")
public #ResponseBody Foo updateFoo(#RequestBody Foo foo) {
fooService.update(foo);
}
//PUT method #2
#RequestMapping(method=RequestMethod.PUT, value="/foo", headers="returnType=FooExtra")
public #ResponseBody FooExtra updateFoo(#RequestBody FooExtra fooExtra) {
fooService.update(fooExtra);
}
Note also that if you want to access a return value with #ResponseBody you have to return your object, otherwise make the methods void
For understanding it we should think how Spring works, it uses Dispatcher Servlet. I don't think that spring does "combine" work for different types of input.
So my answer will be: "trick" with two different urls ;)

Categories