retrofit icon indicating copy to clipboard operation
retrofit copied to clipboard

Retrofit 3.x Things

Open JakeWharton opened this issue 8 years ago • 55 comments

Currently no plans for a Retrofit 3.x. Just tracking changes in a single issue instead of many.

  • Mock behavior should invoke the implementation method for each Call.execute() / Call.enqueue(). Currently it only invokes it once and reuses the result for every cloned Call.
  • Eliminate Retrofit-wide knowledge of callback executor. This should be at best a first-party CallAdapter.Factory which you can apply (if you want) and which can target all calls or just those annotated with something like @MainThread.

JakeWharton avatar Jan 30 '17 06:01 JakeWharton

Will there be a simple way in order to retry a call n times? This would come very handy when there is a call that should be retried after an error. I was hoping for something like: request.retry(5);

TobiasReich avatar Feb 03 '17 09:02 TobiasReich

To do this with Observables we use a custom transformer that gets tacked onto request invocations that takes in the number of retries.

naturalwarren avatar Feb 03 '17 17:02 naturalwarren

Curious if for a 3.x it would be appropriate to have HttpException be a part of the retrofit module, instead of creating it separately in each adapter that is created. Is there a reason for this currently?

Jawnnypoo avatar Feb 10 '17 23:02 Jawnnypoo

There's no use for it in the main module at present which is why each adapter defines its own. This change wouldn't need to wait for 3.x as it can be added in a backwards compatible-way.

On Fri, Feb 10, 2017, 6:24 PM John [email protected] wrote:

Curious if for a 3.x it would be appropriate to have HttpException be a part of the retrofit module, instead of creating it separately in each adapter that is created. Is there a reason for this currently?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/2180#issuecomment-279093946, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEbkNipR8MdHziHDxfyQPhnG58fbAks5rbPG8gaJpZM4LxEk6 .

JakeWharton avatar Feb 10 '17 23:02 JakeWharton

Gotcha. So do you think that each should continue to have its own copy? The benefits I could see with unifying mostly come from just reducing the duplication. Is this something you would be interested in seeing in a PR, or do you prefer keeping them separate?

Jawnnypoo avatar Feb 10 '17 23:02 Jawnnypoo

I'd be okay with a PR. Basically copy paste it into the main module and then change all the existing ones to extend. I'm not happy it has to be non-final in the main module, but it's only an exception so not a big deal.

On Fri, Feb 10, 2017, 6:48 PM John [email protected] wrote:

Gotcha. So do you think that each should continue to have its own copy? The benefits I could see with unifying mostly come from just reducing the duplication. Is this something you would be interested in seeing in a PR, or do you prefer keeping them separate?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/2180#issuecomment-279097602, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEd7JMYB1r3-DiOeglVnbi7LAApT5ks5rbPdmgaJpZM4LxEk6 .

JakeWharton avatar Feb 11 '17 03:02 JakeWharton

I created #2194 to track that. Feel free to send a PR over the weekend. Otherwise I'll grab it on Monday. I need to release really soon but I'll wait for this.

JakeWharton avatar Feb 11 '17 05:02 JakeWharton

@TobiasReich no plans for retry. You can already call clone() on a Call to retry and so implementing that at the application level seems more appropriate. You can write a CallAdapter to return a custom type that provides a nice API for retry. Because of the behavior in sync vs. async mode and what executor the delay happens on being unclear I don't think I want it in the library.

JakeWharton avatar Feb 11 '17 05:02 JakeWharton

You can add code below to your okhttp interceptor to archieve retry mechanism.

new OkHttpClient.Builder()
  .addInterceptor(new RetryInterceptor(3)) // must add at first
  // ...
  .build();

The RetryInterceptor is

public class RetryInterceptor implements Interceptor {
  private final int mRetryTimes;

  public RetryInterceptor(int retryTimes) {
    mRetryTimes = retryTimes;
  }

  @Override
  public Response intercept(Chain chain) throws IOException {
    int retryTimesLeft = mRetryTimes;
    for (; retryTimesLeft > 0; --retryTimesLeft) {
      try {
        return chain.proceed(chain.request());
      } catch (IOException ignore) {
      }
    }
    throw new IOException("still fail after retry " + mRetryTimes + " times");
  }
}

The code is not tested yet. But I think it's quite simple to understand.

ylfzq avatar Feb 28 '17 05:02 ylfzq

Kotlin Will retrofit support async/await in future?

Skullper avatar Mar 26 '17 09:03 Skullper

~It already does https://github.com/gildor/kotlin-coroutines-retrofit~

Built-in now

On Sun, Mar 26, 2017, 5:03 AM Skullper [email protected] wrote:

Kotlin Will retrofit support async/await in future?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/2180#issuecomment-289267555, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEXo8FGgr0JKhEFIJbBbn1L7ZS4HFks5rpinTgaJpZM4LxEk6 .

JakeWharton avatar Mar 26 '17 16:03 JakeWharton

Return easy error api from Retrofit1.

msangel avatar Aug 12 '17 16:08 msangel

@JakeWharton Can we remove HttpException in 3.x? Since it has been unified across the modules here: https://github.com/square/retrofit/commit/4546d5d88a331db779e72fbf453bc5abd69edd2d.

jaredsburrows avatar Aug 28 '17 15:08 jaredsburrows

Everything deprecated gets removed in major version bumps.

On Mon, Aug 28, 2017 at 11:41 AM Jared Burrows [email protected] wrote:

@JakeWharton https://github.com/jakewharton Can we remove HttpException in 3.x? Since it has been unified across the modules here: 4546d5d https://github.com/square/retrofit/commit/4546d5d88a331db779e72fbf453bc5abd69edd2d .

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/2180#issuecomment-325390373, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEVOG3Mw1AuQvlTPjsxh591r7LlgIks5sct-TgaJpZM4LxEk6 .

JakeWharton avatar Aug 28 '17 15:08 JakeWharton

@JakeWharton Great.

jaredsburrows avatar Aug 28 '17 15:08 jaredsburrows

Thanks. That's what I was asked for.

msangel avatar Aug 28 '17 16:08 msangel

It wasn't what you were asking for. The error handling of 1.x was terribly designed (by me) and will not be returning.

On Mon, Aug 28, 2017 at 12:20 PM Vasyl Khrystyuk [email protected] wrote:

Thanks. That's what I was asked for.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/2180#issuecomment-325401394, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEUz50bLGSZclpRkDek-gy7xDnS9Qks5scujlgaJpZM4LxEk6 .

JakeWharton avatar Aug 28 '17 16:08 JakeWharton

Most of people get http error with adequate, well-formatted message. Yep, not all. But still, most cases the response can be converted well with built-in or custom converters, like those for 2xx responces. And this works perfect in version1. People need this. On stackoverflow I saw workarounds like creating new retrofit instance(or getting instance as singletons) just for accessing converters. Or others solutions(http://bytes.babbel.com/en/articles/2016-03-16-retrofit2-rxjava-error-handling.html)

msangel avatar Aug 28 '17 17:08 msangel

Your assumptions are incorrect. The samples show how to correctly handle the case where you want to deserialize error responses using a converter.

On Mon, Aug 28, 2017 at 1:02 PM Vasyl Khrystyuk [email protected] wrote:

Most of people get http error with adequate, well-formatted message. Yep, not all. But still, most cases the response can be converted well with built-in or custom converters, like those for 2xx responces. And this works perfect in version1. People need this. On stackowerflow I saw workarounds like creating new retrofit instance(or getting instance as singletons) just for accessing converters. Or others solutions( http://bytes.babbel.com/en/articles/2016-03-16-retrofit2-rxjava-error-handling.html )

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/2180#issuecomment-325412378, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEaxFtJ7xQPXYfPQicQIs8P5xqonjks5scvKJgaJpZM4LxEk6 .

JakeWharton avatar Aug 28 '17 17:08 JakeWharton

@msangel Here is the sample: https://github.com/square/retrofit/blob/master/samples/src/main/java/com/example/retrofit/ErrorHandlingAdapter.java.

jaredsburrows avatar Aug 28 '17 17:08 jaredsburrows

That one doesn't really cover it. I guess there isn't a sample for it. It's a combination of https://github.com/square/retrofit/blob/e6a7cd01657670807bed24f6f4ed56eb59c9c9ab/samples/src/main/java/com/example/retrofit/DeserializeErrorBody.java and https://speakerdeck.com/jakewharton/making-retrofit-work-for-you-droidcon-uk-2016?slide=214

JakeWharton avatar Aug 28 '17 17:08 JakeWharton

Yep. The first sample is good. It is worst then retrofit1 solution just in that moment that error know nothing about it's context. Adding to the error (transient) link to the retrofit instance it was created with will solve the gap. And maybe adding method like getErrorBodyAs(SomeType.class) to the HttpError will fulfill it completely.

msangel avatar Aug 29 '17 03:08 msangel

That is not possible because of serialization requirements.

On Mon, Aug 28, 2017, 11:40 PM Vasyl Khrystyuk [email protected] wrote:

Yep. The first sample is good. It is worst then retrofit1 solution just in that moment that error know nothing about it's context. Adding to the error (transient) link to the retrofit instance it was created with will solve the gap. And maybe adding method like getErrorBodyAs(SomeType.class) to the HttpError will fulfill it completely.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/2180#issuecomment-325546147, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEbrvCznhcf7fVD9Yk9YCJGRdPZfxks5sc4gxgaJpZM4LxEk6 .

JakeWharton avatar Aug 29 '17 03:08 JakeWharton

Any plan to support custom annotation on an interface in 3.x?

vidhithakrar avatar Sep 07 '17 09:09 vidhithakrar

I don't know what that means

On Thu, Sep 7, 2017 at 5:26 AM vidhithakrar [email protected] wrote:

Any plan to support custom annotation on an interface in 3.x?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/2180#issuecomment-327745074, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEZwme3tpMmZcMDerpUUaaLRSlBsrks5sf7bTgaJpZM4LxEk6 .

JakeWharton avatar Sep 07 '17 13:09 JakeWharton

Perhaps something like:

@BaseUrl("https://host1.mydomain.com")
public interface MyService1 {
    @GET("get_something")
    Call<Something> getSomething();
    // ... Many other methods that use the same baseUrl
}

Where @BaseUrl is a user-defined annotation. Then CallAdapter.Factory should receive not just method annotations but also the annotations declared on the interface. I can imagine why this could be useful. Instead of creating a customized Retrofit client before calling retrofit.create(X.class) one could create a custom CallAdapter.Factory that would parse those annotations and provide an accordingly customized Retrofit instance to a CallAdapter.

technoir42 avatar Sep 07 '17 15:09 technoir42

@zergtmn Yes, something like that. One more thing to add is we get Method level annotation in the CallAdapterFactory but not the Method Parameter level.

public interface FooServices {
    @GET("/path")
    @MethodCustom
    Call<Foo> foo(@Custom String custom);
}

In the CallAdapterFactory, We get @MethodCustom annotation but not the @Custom.

vidhithakrar avatar Sep 07 '17 17:09 vidhithakrar

I see no use to doing that. What would you use it for?

On Thu, Sep 7, 2017 at 1:38 PM vidhithakrar [email protected] wrote:

@zergtmn https://github.com/zergtmn Yeah, something like that. One more thing to add is we get Method level annotation in the CallAdapterFactory but not the Method Parameter level.

public interface FooServices { @get https://github.com/get("/path") Call foo(@Custom https://github.com/custom String custom); }

We do not get

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/2180#issuecomment-327862504, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEVczlTigK-cNrHpzIZkScuDF3VDUks5sgCIlgaJpZM4LxEk6 .

JakeWharton avatar Sep 07 '17 17:09 JakeWharton

One major point on my whish-list for Retrofit 3 is better type converters. Moshi does this excellently and Google's Room is by far the most intuitive solution. I know that Retrofit is a bit different in that it features different adapters for the request body and for strings, but it feels like the converter API needs some improvement. Think of use cases where you want to have one type converter convert from ResponseBody to Foo and another that can then convert from Foo to Bar. That way you could e.g. parse. I've personally worked on a conversion API some time ago and would be happy to help in the development of Retrofit 3.

janheinrichmerker avatar Oct 21 '17 00:10 janheinrichmerker

Custom annotation example: interface with the filename as a parameter. We are registering a custom handler for methods with such annotations. Then when the method gets called - the execution will be delivered to the handler. So I will read the file, will process it(compress in my case) and will send in the custom manner. And I do not need to write any custom wrapper around the interface just for inject some specific functionality to the generated class. Another case: special custom AUTH, when the credentials are just additional request parameters(quite popular case), so we will write a custom handler that will set the credentials. So setting custom annotation and writing handler for it will solve the problem. Another case: we can write one custom annotation for queries to one host, and the second - for queries to the second host. I believe this annotation should be able to change not only request but the response as well. Actually, you have already builtin logic for convert the response via converters, its good, but still few things there are missing (current retrofit object);

msangel avatar Oct 23 '17 16:10 msangel