-
Notifications
You must be signed in to change notification settings - Fork 435
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
Support running grpc-web in React Native #141
Comments
Hi @begoat, Thanks for raising. Will try to look into it today. Is there anything specific about your |
I setup typescript workflow following this tutorial |
Hi @begoat, I can reproduce the problem but I do not have a fix yet. It appears that react-native does not allow the |
:) |
Hi! I'm also looking into using this lib with react native. React native is more browser-like than node-like. It should support fetch and XMLHttpRequest, see https://facebook.github.io/react-native/docs/network.html Node transport is the last one tried by the factory. So it should select fetch which is first and as a fallback possibly XMLHttpRequest, but not node http. The quesition is: is there a problem with the detection code itself, or is the detection code failing because of some missing sub-feature of fetch/XMLHttpRequest in RN? Did you two find out more during debugging? Any hints, where the problem is? |
The issue is with RN. It's fetch API implementation does not support streaming: facebook/react-native#9629 |
Thank you for the hint. I guess, they don't support overrideMimeType, too. So the remaining options are websockets like in #137 with polling fallback. Or binding the native platform clients of grpc in RN. |
The issue is two fold.
|
I would not recommend Websockets for Mobile; it drains your battery really fast. One benifits of gRPC is its efficiency I.e better on your battery. The best option for RN is to bind to the native gRPC implementations. |
Yeah, currently I use both grpc-java and grpc-objectiveC in my react-native project instead. It won't take too much time to implement them and it works well. |
@easyCZ, Did you mean grpc-web wouldn't used on react-native? |
@easyCZ can we look at migrating away from this http client and into something that react-native will support? |
When I did look into this there has been absolutely no way to support grpc in RN. Every option I checked did not work because details have not been implemented in RN. |
Thanks Rob! |
@RobIsHere did you try this? https://github.com/tradle/react-native-http |
No. But the readme says adapted from stream-http which say „It tries to match Node's API and behavior as closely as possible, but some features aren't available, since browsers don't give nearly as much control over requests.“ |
@begoat @easyCZ After many frustrating hours I got this library working in React Native yesterday using a mix of https://github.com/tradle/rn-nodeify and the following custom transport (based on the xhr one). As already noted React Native has support for the Fetch API but does not support response.body.getReader() or response.arrayBuffer() so there is no way to get the response as raw bytes. I thought I'd be able to get it working with The transport below is based on the XHR transport with the following changes:
import { Metadata } from 'grpc-web-client/dist/metadata';
import {
Transport,
TransportOptions,
} from 'grpc-web-client/dist/transports/Transport';
import detach from 'grpc-web-client/dist/detach';
declare const XMLHttpRequest: any;
class XHR implements Transport {
options: TransportOptions;
xhr: any = null;
metadata: Metadata | null = null;
constructor(transportOptions: TransportOptions) {
this.options = transportOptions;
}
onLoadEvent() {
const result = new Uint8Array(this.xhr.response);
detach(() => {
this.options.onChunk(result);
});
detach(() => {
this.options.onEnd();
});
}
onStateChange() {
if (this.xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
detach(() => {
this.options.onHeaders(
new Metadata(this.xhr.getAllResponseHeaders()),
this.xhr.status
);
});
}
}
sendMessage(msgBytes: Uint8Array) {
this.xhr.send(msgBytes);
}
finishSend() {}
start(metadata: Metadata) {
this.metadata = metadata;
const xhr = new XMLHttpRequest();
this.xhr = xhr;
xhr.open('POST', this.options.url);
(xhr as any).responseType = 'arraybuffer';
this.metadata.forEach((key, values) => {
xhr.setRequestHeader(key, values.join(', '));
});
xhr.addEventListener('readystatechange', this.onStateChange.bind(this));
xhr.addEventListener('loadend', this.onLoadEvent.bind(this));
xhr.addEventListener('error', (err: any) => {
detach(() => {
this.options.onEnd(err.error);
});
});
}
cancel() {
this.xhr.abort();
}
}
export default function xhrTransport(options: TransportOptions): Transport {
return new XHR(options);
} Hope this helps someone 😄 |
Thanks for the contribution!
Could you please consider raising this as pull request and we can look to
get it integrated?
…On Tue, 21 Aug 2018, 09:53 Jon Bretman, ***@***.***> wrote:
@begoat <https://github.com/begoat> @easyCZ <https://github.com/easyCZ>
After many frustrating hours I got this library working in React Native
yesterday using a mix of https://github.com/tradle/rn-nodeify and the
following custom transport (based on the xhr one).
As already noted React Native has support for the Fetch API but does not
support response.body.getReader() or response.arrayBuffer() so there is no
way to get the response as raw bytes. I thought I'd be able to get it
working with response.blob() and then FileReader.readAsDataURL but I
couldn't seem to get the base64 string back into a Uint8Array without it
being corrupted.
The transport below is based on the XHR transport with the following
changes:
- removed overrideMimeType as this is not supported in React Native
- responseType is set to 'arraybuffer'
- not listening for the 'progress' event - this never seems to fire
- due to the previous point the response body is read in the 'loadend'
handler
import { Metadata } from 'grpc-web-client/dist/metadata';import {
Transport,
TransportOptions,
} from 'grpc-web-client/dist/transports/Transport';import detach from 'grpc-web-client/dist/detach';
declare const XMLHttpRequest: any;
class XHR implements Transport {
options: TransportOptions;
xhr: any = null;
metadata: Metadata | null = null;
constructor(transportOptions: TransportOptions) {
this.options = transportOptions;
}
onLoadEvent() {
const result = new Uint8Array(this.xhr.response);
detach(() => {
this.options.onChunk(result);
});
detach(() => {
this.options.onEnd();
});
}
onStateChange() {
if (this.xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
detach(() => {
this.options.onHeaders(
new Metadata(this.xhr.getAllResponseHeaders()),
this.xhr.status
);
});
}
}
sendMessage(msgBytes: Uint8Array) {
this.xhr.send(msgBytes);
}
finishSend() {}
start(metadata: Metadata) {
this.metadata = metadata;
const xhr = new XMLHttpRequest();
this.xhr = xhr;
xhr.open('POST', this.options.url);
(xhr as any).responseType = 'arraybuffer';
this.metadata.forEach((key, values) => {
xhr.setRequestHeader(key, values.join(', '));
});
xhr.addEventListener('readystatechange', this.onStateChange.bind(this));
xhr.addEventListener('loadend', this.onLoadEvent.bind(this));
xhr.addEventListener('error', (err: any) => {
detach(() => {
this.options.onEnd(err.error);
});
});
}
cancel() {
this.xhr.abort();
}
}
export default function xhrTransport(options: TransportOptions): Transport {
return new XHR(options);
}
Hope this helps someone 😄
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#141 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAMN-fo068v546K0rrFfTKcjmCV4RxTOks5uS8pzgaJpZM4SA2OM>
.
|
@jonnyreeves Yeh sure, probably won't have time for another week or so though. In the meantime I will continue to test out my solution on the app I'm working on. Haven't tried it on Android yet... 😟 |
Lets recap; with the transport provided by @jonbretman, we could add support for React Native? Is that correct? Does anything else need to be done? |
@johanbrandhorst, that's correct for support in React Native |
I’m sorry I haven’t had time to look at this yet. It’s also worth noting
that I haven’t tested this on Android so it might be just an iOS thing.
What I can say if we’re now successfully using this on iOS with no issues
so pretty confident it works.
On Mon, 10 Sep 2018 at 01:48, linjson ***@***.***> wrote:
@johanbrandhorst <https://github.com/johanbrandhorst>, that's correct for
support in React Native
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#141 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABl_cUwHpIeZUX0vMt_Dty5bar40_pEcks5uZbbGgaJpZM4SA2OM>
.
--
*Jon Bretman*
*mobile: *0774 555 7381
*email: *jon.bretman@gmail.com
|
@jonbretman that is very exciting to hear. Would you be interested in contributing this transport to the project? |
I would but am just super busy right now. Might have some time over the
next few weeks.
|
Hey all, you seem to be some of the only ones running into my issue. Currently trying to use Are there really no work-arounds to let us use that module? Having to rewrite this provider to use a different request solution would be a real drag. |
@john-osullivan #265 provides a solution by extracting the Node HTTP Transport out from the core project and into a separate module. |
Following on from the conversation in #261 this PR allows the user to configure the behavior of a given Transport, separate from the pre-existing TransportOptions interface which deals with passing request state (ie: host, url, callbacks, etc). To facilitate this change, the transport option passed to the unary, invoke and client functions is now expected to meet the new grpc.TransportFactory interface, ie: a func which can accept zero or more args and will return a grpc.Transport instance. ``` grpc.unary(BookService.GetBook, { request: getBookRequest, host: host, transport: grpc.HttpTransport({ credentials: 'include' }), onEnd: ( /*...*/ ) }); ``` Note this results in a breaking change for anyone currently using the Websocket Transport; instead of specifying: ``` transport: gprc.WebsocketTransportFactory ``` They would instead now call: ``` transport: grpc.WebsocketTransport() ``` This change also spurred me to to fix #191 and #141 by extracting the 'Node HTTP' transport out from the gprc-web-client package and into a new module: grpc-web-node-http-client, which will be published to npm separately. As one thing leads to another, extracting node-grpc-web-node-http-transport led to implement grpc.setDefaultTransport() which allows the user to specify which TransportFactory` should be .invoked if none is supplied in the options. ## Breaking Changes transport option passed to unary, invoke and client is now expected to by an instance of Transport, not a reference to a function which will return a Transport when invoked. grpc-web-client no longer auto-selects a suitable transport in a NodeJS environment; users of grpc-web-client in a NodeJS environment will need to depend upon grpc-web-node-http-transport and make use of grpc.setDefaultTranpsport().
FYI, I'm able to use In order for that transport to work in RN, I had to:
extraNodeModules: {
buffer: require.resolve('buffer/'),
http: require.resolve('stream-http'),
https: require.resolve('https-browserify')
}
global.Buffer = require('buffer').Buffer; My main source for getting to this result was: https://github.com/parshap/node-libs-react-native |
Awesome, thanks for posting this. It would be useful to create a react native example in the repo. Would you be interested in contributing? I'm happy to walk you through the contribution if needed. |
Unfortunately I don't have time for this now. Sorry. |
With #458 I was able to get gRPC-WEB working with RN. Looks pretty similar to what @jonbretman did. |
Any update to this? I haven't been able to get any of these solutions to work. The 'grpc-web-client' no longer has any of those files in list and bourquep's change results in errors. Would be nice to have built in support without hacking around the issue. |
@mikebm You could take a look at https://github.com/improbable-eng/grpc-web/tree/master/client/grpc-web-react-native-transport |
hello guys! Thank you for such hard work around gRPC support in RN! I've tried with I have separate file with Any clues? This is my app info:
|
Did you ever figure this one out? |
Hi, can you please suggest me a proper document on gRPC on react native |
https://reactnative.dev/docs/native-modules-ios Hope this can help. Good luck. |
I tried grpc-web today. But unfortunately errors occurred when send request.
The error log is cannot resolve http module from node_module/grpc-web-client/dist/transports/nodeHttp.js. The version of grpc-web-client is 0.5.0 which is uploaded 3 days ago.
I try to install http npm package, but another error shows that the node_modules/http/package.json was successfully found but this package itself specifies a 'main' module field that couldn't be found.
I also try to install some browserified package instead for example stream-http and change the nodeHttp.js file's requirement, but seems that I will do many serious tweak.
Could someone give me some more suggestions? :)
The text was updated successfully, but these errors were encountered: