Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject configured OkHttpClient to networking module using MainPackageConfig #14068

Closed
wants to merge 4 commits into from

Conversation

thotegowda
Copy link

@thotegowda thotegowda commented May 19, 2017

Motivation

The main purpose of this PR is to enable brownfield applications to inject existingOkHttpClient instance to react-native networking sub system. Most native applications would have their OkHttpClient instance configured with headers, interceptors, logging, fallback handling, error handling, etc. It doesn't make much sense to duplicate all of this to use fetch in javascript. Currently the only way you could use existing OkHttpClient is by custom-bridge to native, but this will stops app from using fetch interface in JS.

With this commit, App can pass OkHttpClient instance to networking module using MainPackageConfig, while creating MainReactPackage.

Test Plan

Unit tests.

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. GH Review: review-needed labels May 19, 2017
thotegowda referenced this pull request in thotegowda/react-native May 19, 2017
}

private OkHttpClient createOkHttpClient(
OkHttpClientProvider okHttpClientProvider,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add the @Nullable annotation just like List<NetworkInterceptorCreator>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes good idea - makes the API clearer to users.

}

/**
* @param context the ReactContext of the application
* @param defaultUserAgent the User-Agent header that will be set for all requests where the
* caller does not provide one explicitly
* @param client the {@link OkHttpClient} to be used for networking
* @param okHttpClientProvider the {@link OkHttpClient} provider to be used for networking
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could update the {@link } to point to the OkHttpClientProvider

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, probably you should just call it provider

Copy link
Contributor

@mkonicek mkonicek May 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both. Maybe httpClientProvider.

}

/**
* @param context the ReactContext of the application
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use the {@link} annotation for the java docs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit @param context the {@link ReactApplicationContext} of the application


public Builder setFrescoConfig(ImagePipelineConfig frescoConfig) {
mFrescoConfig = frescoConfig;
return this;
}

/**
* Ability to inject configured OkHttpClient provider to react-native networking subsystem.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about the {@link} annotation. I also dont think that the sentence This will be very useful is needed.

@@ -77,6 +78,7 @@
@Test
public void testGetWithoutHeaders() throws Exception {
OkHttpClient httpClient = mock(OkHttpClient.class);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit remote

@@ -87,8 +89,10 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
OkHttpClientProvider clientProvider = mock(OkHttpClientProvider.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment than before you can just call it provider

@amilcar-andrade
Copy link
Contributor

@thotegowda I added some minor comments. By the way, I am not an official reviewer but I am going to do something similar to what you are trying to achieve.

@@ -154,7 +154,7 @@ private static ImagePipelineConfig getDefaultConfig(ReactContext context) {
HashSet<RequestListener> requestListeners = new HashSet<>();
requestListeners.add(new SystraceRequestListener());

OkHttpClient client = OkHttpClientProvider.createClient();
OkHttpClient client = new DefaultOkHttpProvider().get();
Copy link
Contributor

@mkonicek mkonicek May 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If fetching images should not be affected by the HTTP provider from MainPackageConfig we should document the MainPackageConfig only affects the fetch API.

It's probably easier, however, to just use the HTTP client configured in MainPackageConfig also here (for fetching images) to avoid confusion.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked in to the details of how Fresco is using this client. But I guess, Fresco might need its own customised client configuration.

For now, I will add a comment in MainPackageConfig. Will take a look at this later. Would be great if someone with Fresco context can share some light.

Copy link
Contributor

@mkonicek mkonicek Jun 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK sounds good, someone else can do that separately and we can keep this pull request simpler.

On Android 4.1-4.4 (API level 16 to 19) TLS 1.1 and 1.2 are
available but not enabled by default. The following method
enables it.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a stylistic thing but I could you make this into a Javadoc please?

Copy link
Contributor

@mkonicek mkonicek May 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the method should be private - it's not used anywhere outside this class. I see it was public and just moved - so it was wrong previously but now is a good opportunity to make it private.

specs.add(ConnectionSpec.CLEARTEXT);

client.connectionSpecs(specs);
} catch (Exception exc) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Please name this variable e - another opportunity to fix existing code a bit.


client.connectionSpecs(specs);
} catch (Exception exc) {
FLog.e("OkHttpClientProvider", "Error while enabling TLS 1.2", exc);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be Flog.e(ReactConstants.TAG, "Error while enabling TLS 1.2", e); so it's easy to see all React Native related messages in logcat.

Again I realise this is just moved code but good opportunity for minor fixes.

FLog.e("OkHttpClientProvider", "Error while enabling TLS 1.2", exc);
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Empty line not really needed.


/**
* Helper class that provides the same OkHttpClient instance that will be used for all networking
* requests.
* Interface that provides the OkHttpClient instance, that will be used for all networking requests.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor nit: No need for comma before "that".


/**
* Configuration for {@link MainReactPackage}
*/
public class MainPackageConfig {

private ImagePipelineConfig mFrescoConfig;

private final OkHttpClientProvider mOkHttpClientProvider;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO mHttpClientProvider would be as clear as it's shorter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be @Nullable.

assertEquals(config.getOkHttpClientProvider().getClass(), DefaultOkHttpProvider.class);
}

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks for adding this! 💯

@mkonicek
Copy link
Contributor

mkonicek commented May 22, 2017

Thanks for doing this! I get the motivation for doing this and think the PR makes a lot of sense. Left some quite minor comments and once you address them we can merge.

@thotegowda
Copy link
Author

@mkonicek @amilcar-andrade Incorporated your feedback points. Please check.


/**
* @param context the ReactContext of the application
* @param httpClientProvider {@link OkHttpClientProvider} to provide {@link OkHttpClient}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit extra space httpClientProvider {

@amilcar-andrade
Copy link
Contributor

@thotegowda cool. I think it looks good. But again I cannot merge or approve your PR. Thanks for doing this it will help a lot of us.

@mkonicek
Copy link
Contributor

mkonicek commented May 30, 2017

Thanks for addressing the comments! I don't have push access anymore but I just messaged contributors asking to merge this.

@amilcar-andrade
Copy link
Contributor

@thotegowda you should probably squash your commits and rebase against master.

@thotegowda
Copy link
Author

@amilcar-andrade - Done squashing commits.
@mkonicek - Thanks a lot for taking interest in this.

@facebook-github-bot facebook-github-bot added GH Review: accepted Import Started This pull request has been imported. This does not imply the PR has been approved. and removed GH Review: review-needed labels May 31, 2017
@Knight704
Copy link

Sorry to comment here, but is there any way to customize okhttpclient currently without this PR? Just checked that OkHttpClientProvider has mechanics for this (like replaceOkHttpClient), but it seems that this injection isn't used internally in networking module

@thotegowda
Copy link
Author

@Knight704 I had used replaceOkHttpClient before. But then one of the recent commit broke it. check commit and discussion here

@Knight704
Copy link

@thotegowda, thanks, got it. So, if I understood correctly, now there is no way to do that, sad 👎

@Knight704
Copy link

Okay, I came up to the workaround for this problem for now:

  1. Extend MainReactPackage
  2. Override method that return native modules and replace Networking provider with custom one,
  3. In this custom provider return default NetworkingModule which has constructor that accept OkHttpClient. (But this constructor is package private and you have to put this custom provider inside facebook package to relax it's access).

@tomoima525
Copy link
Contributor

@hramos Hi, what is the status for this PR?

@hramos
Copy link
Contributor

hramos commented Aug 31, 2017

No news to share. It's on someone's queue internally, waiting for review. As it happens, merging this would require making additional changes to other apps in our internal code repository, which introduces a high level of friction that may keep this PR from getting handled any time soon.

@tomoima525
Copy link
Contributor

@hramos I see. So there is no good way to use Stetho which requires intercepting OkHttp Header

@codebymikey
Copy link

I'm really surprised this PR hasn't been merged in yet.
Anyways @tomoima525, I was able to workaround the issue a couple of months back using a variant of @Knight704 approach.

Here is a gist of it. Hope it's helpful.

Also @hramos, surely this is a relatively easy fix with almost no chance of breaking the existing tests/logic. Thoughts?

@facebook-github-bot
Copy link
Contributor

@thotegowda I tried to find reviewers for this pull request and wanted to ping them to take another look. However, based on the blame information for the files in this pull request I couldn't find any reviewers. This sometimes happens when the files in the pull request are new or don't exist on master anymore. Is this pull request still relevant? If yes could you please rebase? In case you know who has context on this code feel free to mention them in a comment (one person is fine). Thanks for reading and hope you will continue contributing to the project.

@leon087
Copy link

leon087 commented Nov 28, 2017

@hramos hi,what about this PR? #14675

@AvivRubys
Copy link

Any updates on this PR? I'd love to help if I can, but I'm not even sure what is this waiting for.

@hey99xx
Copy link

hey99xx commented Jan 9, 2018

Any updates on this @hramos ?

If FB will not pull this in, can someone at least give an informal ship-it that confirms that the final code that will be merged will look like the current state of the PR. That way companies with brown-field apps that already compile RN in-house can manually make the same change and patch existing versions of RN between 0.43 and 0.52.

It's on someone's queue internally, waiting for review.

Also how long is this internal queue? It's been 4.5 months since that comment :S :(

facebook-github-bot pushed a commit that referenced this pull request Jan 30, 2018
Summary:
Prior to 0a71f48, users could customise the OkHttp client used by React Native on Android by calling replaceOkHttpClient in OkHttpClientProvider.

This functionality has a variety of legitimate applications from changing connection timeouts or pool size to Stetho integration. The challenge is to add back support for replacing the client without causing a breaking change or reintroducing the problems olegbl sought to address in his original commit.

Introducing a client factory archives these aims, it adds a new, backwards compatible interface and is called each time a client is requested rather than re-using the same instance (unless you explicitly want this behaviour, in which case you could replicate it using a static class property inside your custom factory).

A number of PRs have been opened to add this functionality: #14675, #14068.

I don't have a lot of Java experience so I'm open to better/more idiomatic ways to achieve this :)

Create React Native application and set a custom factory in the constructor, e.g.  `OkHttpClientProvider.setOkHttpClientFactory(new CustomNetworkModule());`

Where a custom factory would look like:

```
class CustomNetworkModule implements OkHttpClientFactory {
    public OkHttpClient createNewNetworkModuleClient() {
        return new OkHttpClient.Builder().build();
    }
}
```

Remove the existing replace client method to prevent accident use and alert existing users that its functionality has changed: #16972

[Android] [Minor] [Networking] - | Provide interface for customising the OkHttp client used by React Native |
Closes #17237

Differential Revision: D6837734

Pulled By: hramos

fbshipit-source-id: 81e63df7716e6f9039ea12e99233f6336c6dd7ef
@hey99xx
Copy link

hey99xx commented Feb 1, 2018

Any updates?

Edit: If #17237 will be the preferred solution, we can actually close this now. I am ok with either pull-request, and the other one looks to be less invasive to me.

jsworx pushed a commit to jsworx/react-native that referenced this pull request Feb 1, 2018
Summary:
Prior to 0a71f48, users could customise the OkHttp client used by React Native on Android by calling replaceOkHttpClient in OkHttpClientProvider.

This functionality has a variety of legitimate applications from changing connection timeouts or pool size to Stetho integration. The challenge is to add back support for replacing the client without causing a breaking change or reintroducing the problems olegbl sought to address in his original commit.

Introducing a client factory archives these aims, it adds a new, backwards compatible interface and is called each time a client is requested rather than re-using the same instance (unless you explicitly want this behaviour, in which case you could replicate it using a static class property inside your custom factory).

A number of PRs have been opened to add this functionality: facebook#14675, facebook#14068.

I don't have a lot of Java experience so I'm open to better/more idiomatic ways to achieve this :)

Create React Native application and set a custom factory in the constructor, e.g.  `OkHttpClientProvider.setOkHttpClientFactory(new CustomNetworkModule());`

Where a custom factory would look like:

```
class CustomNetworkModule implements OkHttpClientFactory {
    public OkHttpClient createNewNetworkModuleClient() {
        return new OkHttpClient.Builder().build();
    }
}
```

Remove the existing replace client method to prevent accident use and alert existing users that its functionality has changed: facebook#16972

[Android] [Minor] [Networking] - | Provide interface for customising the OkHttp client used by React Native |
Closes facebook#17237

Differential Revision: D6837734

Pulled By: hramos

fbshipit-source-id: 81e63df7716e6f9039ea12e99233f6336c6dd7ef
Plo4ox pushed a commit to Plo4ox/react-native that referenced this pull request Feb 17, 2018
Summary:
Prior to 0a71f48, users could customise the OkHttp client used by React Native on Android by calling replaceOkHttpClient in OkHttpClientProvider.

This functionality has a variety of legitimate applications from changing connection timeouts or pool size to Stetho integration. The challenge is to add back support for replacing the client without causing a breaking change or reintroducing the problems olegbl sought to address in his original commit.

Introducing a client factory archives these aims, it adds a new, backwards compatible interface and is called each time a client is requested rather than re-using the same instance (unless you explicitly want this behaviour, in which case you could replicate it using a static class property inside your custom factory).

A number of PRs have been opened to add this functionality: facebook#14675, facebook#14068.

I don't have a lot of Java experience so I'm open to better/more idiomatic ways to achieve this :)

Create React Native application and set a custom factory in the constructor, e.g.  `OkHttpClientProvider.setOkHttpClientFactory(new CustomNetworkModule());`

Where a custom factory would look like:

```
class CustomNetworkModule implements OkHttpClientFactory {
    public OkHttpClient createNewNetworkModuleClient() {
        return new OkHttpClient.Builder().build();
    }
}
```

Remove the existing replace client method to prevent accident use and alert existing users that its functionality has changed: facebook#16972

[Android] [Minor] [Networking] - | Provide interface for customising the OkHttp client used by React Native |
Closes facebook#17237

Differential Revision: D6837734

Pulled By: hramos

fbshipit-source-id: 81e63df7716e6f9039ea12e99233f6336c6dd7ef
@react-native-bot react-native-bot added Missing Changelog This PR appears to be missing a changelog, or they are incorrectly formatted. Ran Commands One of our bots successfully processed a command. labels Mar 16, 2018
@hey99xx
Copy link

hey99xx commented Jun 12, 2018

@hramos Given that 22efd95 got released with 0.54, this PR is no longer necessary. They were achieving the same thing through different implementations, but it's hard to keep them both. Can we close this issue?

@hramos hramos closed this Jun 12, 2018
facebook-github-bot pushed a commit that referenced this pull request Jan 28, 2019
Summary:
This method was originally intended to replace the OkHttp client used by React Native's networking library. However it has effectively been a noop since 0a71f48#diff-177100ae5a977e4060b54cc2b34c79a7, when the Networking library was modified to create a new client rather than use the reference provided by OkHttpClientProvider.

Leaving this code in place is dangerous. There is no indication to users upgrading React Native that the method is no longer replacing the OkHttpClient used by the Networking library. Any functionality reliant on overriding the client will silently break. This caused us some problems internally.

There's been a PR out for some time that seeks to reintroduce this functionality: #14068

I've also put up a new PR that adds an interface for replacing the client without introducing breaking changes: #17237

Do our unit tests continue to pass? Should be safe as this method is not used anywhere inside React Native.

[ANDROID] [BREAKING] [Networking] - removed replaceOkHttpClient method in OkHttpClientProvider.
Pull Request resolved: #16972

Differential Revision: D13838805

Pulled By: cpojer

fbshipit-source-id: 43606d1d141afb9b5dda4dd64e5ac5448771b45c
matt-oakes pushed a commit to matt-oakes/react-native that referenced this pull request Feb 7, 2019
Summary:
This method was originally intended to replace the OkHttp client used by React Native's networking library. However it has effectively been a noop since facebook@0a71f48#diff-177100ae5a977e4060b54cc2b34c79a7, when the Networking library was modified to create a new client rather than use the reference provided by OkHttpClientProvider.

Leaving this code in place is dangerous. There is no indication to users upgrading React Native that the method is no longer replacing the OkHttpClient used by the Networking library. Any functionality reliant on overriding the client will silently break. This caused us some problems internally.

There's been a PR out for some time that seeks to reintroduce this functionality: facebook#14068

I've also put up a new PR that adds an interface for replacing the client without introducing breaking changes: facebook#17237

Do our unit tests continue to pass? Should be safe as this method is not used anywhere inside React Native.

[ANDROID] [BREAKING] [Networking] - removed replaceOkHttpClient method in OkHttpClientProvider.
Pull Request resolved: facebook#16972

Differential Revision: D13838805

Pulled By: cpojer

fbshipit-source-id: 43606d1d141afb9b5dda4dd64e5ac5448771b45c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Import Started This pull request has been imported. This does not imply the PR has been approved. Missing Changelog This PR appears to be missing a changelog, or they are incorrectly formatted. Ran Commands One of our bots successfully processed a command.
Projects
None yet
Development

Successfully merging this pull request may close these issues.