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.
Related
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);
Right now, I have some endpoints in a resource. These endpoints access some data and return it:
#Path("/v1/event")
#Produces({MediaType.APPLICATION_JSON})
public class EventResource {
private final DataStore dataStore;
// constructor stuff
#Timed
#GET
#Path("/all/total")
public String getAll(#Bind({Bind.Params.QUERY}) Params params) throws Exception {
return dataStore.getEventTotals(params);
}
}
We completely revamped how our data is stored so now I have a resource that accesses this new data store:
#Path("/v2/event")
#Produces({MediaType.APPLICATION_JSON})
public class NewEventResource {
private final NewDataStore newDataStore;
// constructor stuff
#Timed
#GET
#Path("/all/total")
public MyDataPojo getAll(#Bind({Bind.Params.QUERY}) Params params) throws Exception {
return newDataStore.getEventTotals(params);
}
}
What I would like to do now is somehow have the v1 endpoint use both these resources. Some object would decide which getAll method to use based on some parameters in the Params object that is passed in.
The reason is we have some customers that have data in the old data store, and other customers have data in the new data store. We also have a bunch of other projects that are using our endpoints. It's not feasible or realistic to go change all the other projects to use the v2 endpoint instead of the v1 endpoint.
A couple thoughts. I could do something like this:
#Path("/v1/event")
#Produces({MediaType.APPLICATION_JSON})
public class EventResource {
private final DataStore dataStore;
private final NewDataStore newDataStore;
// constructor stuff
#Timed
#GET
#Path("/all/total")
public String getAllEndpoint(#Bind({Bind.Params.QUERY}) Params params) throws Exception {
if (customerInNewDataStore(params.getCustomer())) {
return getEventTotalsNew(params);
} else {
return getEventTotalsOld(params);
}
}
private MyDataPojo getEventTotalsNew(Params params) throws Exception {
return newDataStore.getEventTotals(params);
}
private String getEventTotalsOld(Params params) throws Exception {
return dataStore.getEventTotals(params);
}
}
The problem with this is that getEvenTotalsNew and getEventTotalsOld return different types. How would I be able to merge this? Also, doing this would be sort of a pain to do for every endpoint as there are quite a few endpoints in our codebase.
I've been reading about filters and intercepters in Jersey: https://jersey.java.net/documentation/latest/filters-and-interceptors.html.
Would a ContainerRequestFilter be able to accomplish what I want to do? Would I be able to access my Params params object in the filter?
Any other better ways to do this? I'm open to all ideas.
Thanks!
I think I might have what you are looking for. You can use a pre-matching filter to modify the request.
This is based on your example stating that you have a v1 and v2 API, both of which are equal (apart from the versioning). I am using a custom header for routing.
Consider these two resources:
#Path("v1")
#Produces(MediaType.APPLICATION_JSON)
public class TestResource1 {
#GET
#Path("test")
public String get() {
return "Hello v1";
}
}
#Path("v2")
#Produces(MediaType.APPLICATION_JSON)
public class TestResource2 {
#GET
#Path("test")
public MyResultObj get() {
MyResultObj o = new MyResultObj();
o.name = "pandaa";
o.message = "Hello V2";
return o;
}
public static class MyResultObj {
#JsonProperty
String name;
#JsonProperty
String message;
}
}
These are both equal with the exception for the version type in the context and the return type. Note, the return type does not matter in this case. What ends up in the response is a json string regardless. In your case, you could also do something like:
Response.ok(myResultObject).build();
At that point all of your return types would just be Response.
Anyhow, Version 1 prints something, and version 2 returns an object.
The pre-matching (important, otherwise you can not change the URI) filter will look like this:
#PreMatching
public class RoutingFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String headerString = requestContext.getHeaderString("IS_V2");
boolean v2 = headerString != null && headerString.equals("yes");
URI absolutePath = requestContext.getUriInfo().getAbsolutePath();
if(v2) {
URI v2Redirect = URI.create(absolutePath.toString().replace("v1", "v2"));
requestContext.setRequestUri(v2Redirect);
}
}
}
It simply evaluates the header and replaces the version in the URI. There is probably a better way to do this, but then again this is just an example of how to approach this.
Finally, the test:
artur#pandaadb:~/dev/vpn$ curl "localhost:9085/api/v1/test" --header "IS_V2: yes"
{"name":"pandaa","message":"Hello V2"}
artur#pandaadb:~/dev/vpn$ curl "localhost:9085/api/v1/test" --header "IS_V2: no"
Hello v1
Note how both are doing a request for V1. The first request though gets rerouted internally to v2.
You can write a more generic version (since you might need to be backwards compatible e.g. v1 -> v2 and v2 -> v1) so that it doesn't matter if people call v1 or v2.
Finally - I am not at all sure if this is a good solution :) Personally I would probably write a delegate as seen in your example.
I hope that helps!
Edit: finally - you should be able to use your params object. However this may result in you consuming the requests's input stream. I believe this can only be done once, so you may need to set a new stream after reading it as well.
Artur
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>
}
I have a service in rest that looks like:
#GET
#Path("get-policy/{policyNumber}/{endorsement}/{type}")
#Produces(MediaType.APPLICATION_XML)
public String getPolicyIndividual(
#PathParam("policyNumber")String policyNumber,
#PathParam("endorsement")String endorsement,
#PathParam("type")String type){
...
}
And i want to know if there is a way that i can accept every parameter as null value if they are not sent, so if somene makes a call to my service without the params or with not all the params still can match the definition of my service.
Examples:
http://localhost:8080/service/policy/get-policy/
or this:
http://localhost:8080/service/policy/get-policy/5568
or this:
http://localhost:8080/service/policy/get-policy/5568/4
Im well aware that i can define a regex expression like in this answer, but in that case there was only 1 path param defined, what if i have more than one?
That didnt work for me but maybe im doing something wrong, i tried this with no success:
#GET
#Path("get-policy/{policyNumber: .*}/{endorsement: .*}/{type: .*}")
#Produces(MediaType.APPLICATION_XML)
public String getPolicyIndividual(
#PathParam("policyNumber")String policyNumber,
#PathParam("endorsement")String endorsement,
#PathParam("type")String type){
...
}
is the only way to achive this trough a POST? Im using Jersey btw!
You have to create a complete use case scenario for this and call a general method every time if you dont want to write code multiple times.
Say: For an instance use only one parameter passed, then 2 and then all, and none
#GET
#Path("get-policy/{policyNumber: .*}")
#Produces(MediaType.APPLICATION_XML)
public String getPolicyIndividual(
#PathParam("policyNumber")String policyNumber)
{
doSomething(policyNumber, "", "");
}
#GET
#Path("get-policy/{policyNumber: .*}/{endorsement: .*}")
#Produces(MediaType.APPLICATION_XML)
public String getPolicyIndividual(
#PathParam("policyNumber")String policyNumber,
#PathParam("endorsement")String endorsement)
{
doSomething(policyNumber,endorsement, "");
}
I have created simple rest service #GET and takes 2 parameters username and password.
I m trying to search how to pass parameters through rest service client and how to get it using the method. I am unable to get the exact answer I want.
How can I pass parameters and how to use that in my webservice?
I don't know what framework you are using but if you use Spring, you can do it like this:
#Controller
public class SampleController {
#RequestMapping(value="/test/{name}/{password}", method = RequestMethod.GET)
public String doTest(#PathVariable String name,#PathVariable String password, ModelMap model) {
System.out.println("REST paras name:"+name+",password:"+password);
return "samplePage";
}
}
then ,url path like [/test/{name}/info] [/test/{name}/info.*] [/test/{name}/info/]
will pass to this method!
You should look on something like:
#HeaderParam or #PathParam
in Jersey it looks like:
#Get
#Path("/mywebservice")
public Response myWebService(#HeaderParam String username,
#HeaderParam String password)
{
...
}
but you should remember that this way of sending/receiving username and password isn't too secure ;)