How to set parameter in interface in retrofit request - java

There is an interface for retrofit:
public interface GetDataService {
#GET("/news")
Call<ItemAPI> getAllItems();
}
How I can give parameters when I do the request? For example,
/news?id=1001
I think it must be looking like:
#GET("/news?id={id}")
But how do I do it correctly?

#GET("/v1/news_content")
Call<ItemPageAPI> getAllItems(#Query("id") String id);
#Query can add your parameters to the URL by itself.

public interface GetDataService {
#GET("/news?id={id}")
Call<ItemAPI> getAllItems(#Query("id") int id);
}

You can set parameters, headers in this way in the retrofit requests
#Headers("Accept: " + "application/json")
#GET(Constants.GET_PROPERTIES)
fun getFilteredProperties(#Query("access_token") access_token: String,
#Query("lat") lat: String,
#Query("long") long: String,
#Query("current_page") current_page: String,
#Query("location_name") location_name: String
): Call<GetPropertiesPojo>

Please use it like this:
#GET("/news?id={id}")
Call<ItemAPI> getAllItems(#Path("id") String idStr);
If the #Path annotation is not working then you can pass in the #Query annotation.

Related

Is there a way to obtain in Spring the list of path variables from the URI?

#RequestMapping(value = "/{ids}", method=RequestMethod.GET)
public String getMethod(#PathVariable List<String> ids){
}
I would like something similar, but I need the request to map to something like: localhost:8080/id1/id2/id3/.../idn
I don’t know the number of path variables (ids) and neither their names.
When you are using a path it essentially adds to the uri . The uri has length limitations.
Related post : Maximum length of HTTP GET request
So it is not advisable to add multiple number of parameters to the uri as path variable, when the number is not restricted.
You could use query params like :
#RequestMapping(value = "/{ids}", method=RequestMethod.GET)
public String getMethod(#RequestParam("myparam") List<String> ids)
{
}
Instead what you could have is convert it to a post request and have a request body with the list of data as an object.
#PostMapping("/")
public ResponseEntity postController(
#RequestBody CustomPojo data) {
exampleService.fakeAuthenticate(data);
return ResponseEntity.ok(HttpStatus.OK);
}
class CustomPoJo {
List<String> ids;
//getter setter etc
}
and the json could look like :
{"custompojo":["id1","id2"]}
It cannot be done since the request will look for endpoint having matching URL and matching method.

Android: Using Retrofit with dynamic urls

I have an url similar to http://www.myexample.com/rss/choose.php?type=level&id=2 and I want to use Retrofit in my android app. The problem is that type is a parameter which can take different values like level, grade, etc.
I can't adapt Retrofit every time type change because I get a "Annotations are not allowed here" in TestesInterface. I was looking to this post and applied to my app but it doesn't work.
static final String BASE_URL = "http://www.myexample.com/rss/";
public void start() {
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(SimpleXmlConverterFactory.create()).build();
TestesInterface testesInterface = retrofit.create(TestesInterface.class);
Call<Channel> call = testesInterface.loadChannel("choose.php?type=level&id=2");
call.enqueue(this);
}
My interface:
public interface TestesInterface {
#GET
Call<Channel> loadChannel(#Url type);
}
This made that every time I want to change type to a different value I should change testesInterface.loadChannel("choose.php?type=level&id=2"). This doesn't work. Can you please help me?
After try different approaches I got the solution.
I had to use the tag #Query to type and id on interface and send the values when I'm invoking it in start():
#GET
Call<Channel> loadChannel(#Query("type") String type,
#Query("id") String value);

how to do a #GET in RXJava in android

I just need to do a #GET for the following endpoint but not sure the syntax, here is my code:
public interface GithubService {
String SERVICE_ENDPOINT = "https://api.github.com";
String SERVICE_FUNDS_ENDPOINT = "http://iwg-testapi.azurewebsites.net";
// this works fine
#GET("/users/{login}")
Observable<Github> getUser(#Path("login") String login);
//here is the problem:
#GET("/stem/funds")
Observable<Funds> getFunds(#Path("funds") String login);
}
It's not a RxJava issue but a Retrofit.
I think the issue is on the GET annotation, as you want to use the path param.
#GET("/stem/{funds}") Observable<Funds> getFunds(#Path("funds")
(Notice that I add {} around funds because I want to use it at the path param)
You may want to check the Retrofit documentation.

Spring MVC - How to return simple String as JSON in Rest Controller

My question is essentially a follow-up to this question.
#RestController
public class TestController
{
#RequestMapping("/getString")
public String getString()
{
return "Hello World";
}
}
In the above, Spring would add "Hello World" into the response body. How can I return a String as a JSON response? I understand that I could add quotes, but that feels more like a hack.
Please provide any examples to help explain this concept.
Note: I don't want this written straight to the HTTP Response body, I want to return the String in JSON format (I'm using my Controller
with RestyGWT which requires the response to be in valid JSON
format).
Either return text/plain (as in Return only string message from Spring MVC 3 Controller) OR wrap your String is some object
public class StringResponse {
private String response;
public StringResponse(String s) {
this.response = s;
}
// get/set omitted...
}
Set your response type to MediaType.APPLICATION_JSON_VALUE (= "application/json")
#RequestMapping(value = "/getString", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
and you'll have a JSON that looks like
{ "response" : "your string value" }
JSON is essentially a String in PHP or JAVA context. That means string which is valid JSON can be returned in response. Following should work.
#RequestMapping(value="/user/addUser", method=RequestMethod.POST)
#ResponseBody
public String addUser(#ModelAttribute("user") User user) {
if (user != null) {
logger.info("Inside addIssuer, adding: " + user.toString());
} else {
logger.info("Inside addIssuer...");
}
users.put(user.getUsername(), user);
return "{\"success\":1}";
}
This is okay for simple string response. But for complex JSON response you should use wrapper class as described by Shaun.
In one project we addressed this using JSONObject (maven dependency info). We chose this because we preferred returning a simple String rather than a wrapper object. An internal helper class could easily be used instead if you don't want to add a new dependency.
Example Usage:
#RestController
public class TestController
{
#RequestMapping("/getString")
public String getString()
{
return JSONObject.quote("Hello World");
}
}
You can easily return JSON with String in property response as following
#RestController
public class TestController {
#RequestMapping(value = "/getString", produces = MediaType.APPLICATION_JSON_VALUE)
public Map getString() {
return Collections.singletonMap("response", "Hello World");
}
}
Simply unregister the default StringHttpMessageConverter instance:
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
/**
* Unregister the default {#link StringHttpMessageConverter} as we want Strings
* to be handled by the JSON converter.
*
* #param converters List of already configured converters
* #see WebMvcConfigurationSupport#addDefaultHttpMessageConverters(List)
*/
#Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(c -> c instanceof StringHttpMessageConverter);
}
}
Tested with both controller action handler methods and controller exception handlers:
#RequestMapping("/foo")
public String produceFoo() {
return "foo";
}
#ExceptionHandler(FooApiException.class)
public String fooException(HttpServletRequest request, Throwable e) {
return e.getMessage();
}
Final notes:
extendMessageConverters is available since Spring 4.1.3, if are running on a previous version you can implement the same technique using configureMessageConverters, it just takes a little bit more work.
This was one approach of many other possible approaches, if your application only ever returns JSON and no other content types, you are better off skipping the default converters and adding a single jackson converter. Another approach is to add the default converters but in different order so that the jackson converter is prior to the string one. This should allow controller action methods to dictate how they want String to be converted depending on the media type of the response.
I know that this question is old but i would like to contribute too:
The main difference between others responses is the hashmap return.
#GetMapping("...")
#ResponseBody
public Map<String, Object> endPointExample(...) {
Map<String, Object> rtn = new LinkedHashMap<>();
rtn.put("pic", image);
rtn.put("potato", "King Potato");
return rtn;
}
This will return:
{"pic":"a17fefab83517fb...beb8ac5a2ae8f0449","potato":"King Potato"}
Make simple:
#GetMapping("/health")
public ResponseEntity<String> healthCheck() {
LOG.info("REST request health check");
return new ResponseEntity<>("{\"status\" : \"UP\"}", HttpStatus.OK);
}
Add produces = "application/json" in #RequestMapping annotation like:
#RequestMapping(value = "api/login", method = RequestMethod.GET, produces = "application/json")
Hint: As a return value, i recommend to use ResponseEntity<List<T>> type. Because the produced data in JSON body need to be an array or an object according to its specifications, rather than a single simple string. It may causes problems sometimes (e.g. Observables in Angular2).
Difference:
returned String as json: "example"
returned List<String> as json: ["example"]
Add #ResponseBody annotation, which will write return data in output stream.
This issue has driven me mad: Spring is such a potent tool and yet, such a simple thing as writing an output String as JSON seems impossible without ugly hacks.
My solution (in Kotlin) that I find the least intrusive and most transparent is to use a controller advice and check whether the request went to a particular set of endpoints (REST API typically since we most often want to return ALL answers from here as JSON and not make specializations in the frontend based on whether the returned data is a plain string ("Don't do JSON deserialization!") or something else ("Do JSON deserialization!")). The positive aspect of this is that the controller remains the same and without hacks.
The supports method makes sure that all requests that were handled by the StringHttpMessageConverter(e.g. the converter that handles the output of all controllers that return plain strings) are processed and in the beforeBodyWrite method, we control in which cases we want to interrupt and convert the output to JSON (and modify headers accordingly).
#ControllerAdvice
class StringToJsonAdvice(val ob: ObjectMapper) : ResponseBodyAdvice<Any?> {
override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean =
converterType === StringHttpMessageConverter::class.java
override fun beforeBodyWrite(
body: Any?,
returnType: MethodParameter,
selectedContentType: MediaType,
selectedConverterType: Class<out HttpMessageConverter<*>>,
request: ServerHttpRequest,
response: ServerHttpResponse
): Any? {
return if (request.uri.path.contains("api")) {
response.getHeaders().contentType = MediaType.APPLICATION_JSON
ob.writeValueAsString(body)
} else body
}
}
I hope in the future that we will get a simple annotation in which we can override which HttpMessageConverter should be used for the output.
Simple and Straightforward send any object or return simple List
#GetMapping("/response2")
#ResponseStatus(HttpStatus.CONFLICT)
#ResponseBody List<String> Response2() {
List<String> response = new ArrayList<>(Arrays.asList("Response2"));
return response;
}
I have added HttpStatus.CONFLICT as Random response to show how to pass RequestBody also the HttpStatus
Annotate your method with the #ResponseBody annotation to tell spring you are not trying to render a view and simple return the string plain

Declaring a retrofit REST endpoint with constant query value

So I want to get the metadata of a youtube video (say this one: https://www.youtube.com/watch?v=qlTA3rnpgzU).
I'm going to encode it and wrap it in another url like so: http://www.youtube.com/oembed?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DqlTA3rnpgzU&format=json
My interface definition will look like this:
public interface YoutubeApi {
#GET ("oembed")
YoutubeMetaData metaData (#Query (QUERY_VIDEO_URL) final String url,
#Query(QUERY_FORMAT) final String alwaysJson);
}
That's all fine and dandy, but I don't ever want to specify any format other than JSON here (format=json is a fixed part of this url).
Is there a way to specify this in my interface declaration and reduce my interface to:
public interface YoutubeApi {
#GET ("oembed")
#Magic ("format=json")
YoutubeMetaData metaData (#Query (QUERY_VIDEO_URL) final String url);
}
Thanks.
Just put it right in the relative URL:
public interface YoutubeApi {
#GET("oembed?format=json")
YoutubeMetaData metaData(#Query(QUERY_VIDEO_URL) String url);
}
In kotlin you can specify the default parameter:
interface YoutubeApi {
#GET ("oembed")
suspend fun metaData (
#Query (QUERY_VIDEO_URL) url: String,
#Query(QUERY_FORMAT) alwaysJson: String = "json"
): Response<YoutubeMetaData>
}

Categories

Resources