Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrofit path replacements: replacement over whole path (including /)

In my setup, I get all the paths for my resources from the REST API from an initial call to the API. We use this pattern to be able to change all the resource paths without breaking all existing app versions in the process.

I have been playing around with Retrofit and I tried to create a method that would accept any path I pass to it as a string. My try looks like this

@GET("/{path}")
public FooBar getFooBar(@Path("path") String path);

I then try to call it as follows.

String path = "foo/bar";
api.getFooBar(path);

Unfortunately Retrofit URL-Encodes the path replacement and I end up making a request to /foo%2Fbar instead of /foo/bar. Is there any way to disable URL-Encoding for path replacements or to make replacements spanning multiple path segments? Unfortunately I don't even know how many path segments there are, it is all controlled by the API.

like image 236
Thrakbad Avatar asked May 23 '14 15:05

Thrakbad


3 Answers

Use @EncodedPath! That's it. I'll copy the Javadoc so this answer has more meat:

Named replacement in the URL path. Values are converted to string using String.valueOf(Object). Values are used literally without URL encoding. See @Path for URL encoding equivalent.

Use it like this:

@GET("/{path}")
void example(@EncodedPath("path") String path, ..);
like image 192
Jake Wharton Avatar answered Nov 12 '22 03:11

Jake Wharton


Since @EncodedPath is deprecated now

Retrofit 1.9:

@GET("/{path}")
void example(@Path(value = "path", encoded = false) String path, ..);

Retrofit 2.*:

@GET("/{path}")
void example(@Path(value = "path", encoded = false) String path, ..);
like image 24
Andrew Avatar answered Nov 12 '22 02:11

Andrew


There are known bugs, and you can watch the bugreport on: Retrofit @Github

There is also a link to possible solutions: Solution @Github

In the end, the message from the retrofit developers is:

"Path replacements that span multiple path segments aren't going to be supported, you should use @Url to build the full relative URL programmatically if the number of path segments varies dynamically."

So if you are in trouble with encode, the solution can be:

Your API for GET:

@GET
Call<Object> Function(@Url String path, @Query("CONTENT") String content);

Your API for POST:

@FormUrlEncoded
@POST
Call<Object> Function(@Url String path, @Field("CONTENT") String content);

And you can call it with this:

String thePath = "www.foo.de/foo/foo2";
Call<Object> call = api.Function(thePath,content);

So with this you dont have the problem to encode something.

But if you are just looking for the normal encode in version 2.* the API has to be like this:

@GET("/{path}")
void example(@Path(value = "path", encoded = false) String path, ..);

Regards

like image 12
Klatschen Avatar answered Nov 12 '22 04:11

Klatschen