javagwtgwt-2.8gwt-jsinteropgwt-elemental

How to use XMLHttpRequest in GWT?


XMLHttpRequest is an alternative for HTTP calls from GWT client side and allows the control over all aspects of requests/responses. But how to use it? javadoc address: http://www.gwtproject.org/javadoc/latest/com/google/gwt/xhr/client/class-use/XMLHttpRequest.html


Solution

  • You haven't mentioned what GWT version you use, so I assume the latest one. It means 2.8.2 or newer.

    Elemental2 is the way to go

    As it is mentioned in comments above, Elemental2 is the right way. I will explain it a bit.

    If you think about future-proof implementation (being aware of GWT3/J2CL new approach), please do not use legacy GWT stuff. It means please use elemental2.dom.XMLHttpRequest instead of com.google.gwt.xhr.client.XMLHttpRequest (the one mentioned by you). Please do not use gwt-user dependency if possible, as it will be deprecated (if it is not already).

    The Elemental2 is an opensource project available here: https://github.com/google/elemental2. It is kind of a base library for the "new GWT". For easier migration of existing GWT2.x projects to GWT3.x, a part of the "old" gwt-user is currently being ported to the new approach using JsInterop technique and mentioned Elemental2. So definitely Elemental2 is the way to go.

    Elemental2 and JsInterop in general

    The specification is not yet that rich if about the new JsInterop approach, but at the moment you will find some introduction at least: http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJsInterop.html

    Examples

    Please find an example for XMLHttpRequest in this article: http://www.g-widgets.com/2016/09/09/gwt-http-requests-alternatives/

    If you look for examples, also a good way is to search this on the Github site this way: https://github.com/search?q=elemental2.dom.XMLHttpRequest&type=Code.

    (To use Github search you need to be logged in, in other case you will see "Whoa there! You have triggered an abuse blah blah..." )

    One of the results will lead you to the very interesting project (you have the preview of the future GWT now): https://github.com/gwtproject/gwt-http. It is a future-proof port of the legacy com.google.gwt.http.HTTP GWT module. It will help to migrate GWT2.x projects to GWT3.x.

    When you look to the test package, you will find some examples: https://github.com/gwtproject/gwt-http/tree/master/src/test/java/org/gwtproject/http/client . So this is finally the answer to your question: "how to use it?" :-)

    An additional examples source for XMLHttpRequest (using Elemental2) from Gist: https://gist.github.com/search?utf8=%E2%9C%93&q=elemental2.dom.XMLHttpRequest. This is probably even better for start, as they are short and clear.

    What Elemental2 is?

    The Elemental2 gives you a type checked access to native browser's API. So if you are familiar with browser's API, you should be able to implement your stuff, even based on some native JavaScript example. Please think about the new GWT like about type safe JavaScript (in addition very performant and well optimized). With JsInterop you create bindings, so it is something similar to bindings for TypeScript. So in fact you have a possibility to deal directly with browser's API, without anything GWT specific.

    Libraries? More examples...?

    Dealing with XMLHttpRequest is a bit low level.

    You have also a possibility to use the library. One of Github search results will lead you to this repository: https://github.com/ibaca/autorest-streaming-example which is an example for interesting REST library: https://github.com/intendia-oss/autorest. A modern and reactive one, works with Observables, RxJava and so on. This library uses JsInterop and is also migrated to Elemental2 what makes it GWT3/J2CL ready, please see the change: https://github.com/intendia-oss/autorest/commit/58516802cd42134544e6e3787207b5431fae94b5 .

    With the Github search query I provided you, now you are able to find even more code examples for XMLHttpRequest. So please just have a look and find the best one for your needs.

    An alternative approach would be to use a framework, for instance Errai from RedHat: http://erraiframework.org/. It helps you to deal with many problems at a different abstraction level.

    I think now you have some references to study.

    On the other hand it's 2018, so why not the Fetch API?

    When think about the modern web application, I would rather think about the Fetch API instead of XMLHttpRequest. All modern browsers now implement the fetch() function natively. Isn't it the best way for solving your issue then? The fetch() is a Promise-based mechanism that allows you to make network requests similar to XMLHttpRequest. Promises and Fetch are handled by Elemental2. Then you can use it from your Java code more or less in similar way like in Mozilla's examples.

    Read more about the Fetch API here:

    What more, this is nothing new as you see. If about the older browsers a polyfill will emulate the missing function: https://github.com/github/fetch.

    If about examples, I don't see that much on Github: https://github.com/search?utf8=%E2%9C%93&q=elemental2.dom.DomGlobal+fetch&type=Code, but at least something.

    The Fetch API seems to be the most current solution to the problem.

    Please find a very simple fetch() example using Elemental2.

    The imports section:

    import static elemental2.dom.DomGlobal.fetch;
    import static elemental2.dom.DomGlobal.console;
    import elemental2.dom.Response;
    

    Then use in your code:

        fetch("https://randomuser.me/api/?gender=female&results=1")
                .then(Response::json)
                .then(data -> {
                    console.log(Global.JSON.stringify(data));
                    return null;
                }).
                catch_(error -> {
                    console.log(error);
                    return null;
                });
    

    As a result you should be able to see something like this:

    {"results":[{"gender":"female","name":{"title":"mrs","first":"caroline","last":"coleman"},"location":{"street":"3703 new road","city":"swansea","state":"leicestershire","postcode":"ZH67 0YS","coordinates":{"latitude":"14.7870","longitude":"-107.8990"},"timezone":{"offset":"-6:00","description":"Central Time (US & Canada), Mexico City"}},"email":"caroline.coleman@example.com","login":{"uuid":"25357d90-cce4-4fe6-a3db-8ab77c0272ba","username":"smallpeacock582","password":"citizen","salt":"VX3s05Ah","md5":"84649cce1db8c6f2cbe33098221aa570","sha1":"005abf7d2ca0ff5b1a0bfd6dcee6d4860ef6e75d","sha256":"caadff0a16e27b0d9893aea483aedc7cf7c4707096c33a58acf44336bb2b54be"},"dob":{"date":"1978-03-14T15:47:16Z","age":40},"registered":{"date":"2013-08-10T19:09:41Z","age":5},"phone":"015396 74385","cell":"0726-723-103","id":{"name":"NINO","value":"JA 32 24 22 P"},"picture":{"large":"https://randomuser.me/api/portraits/women/45.jpg","medium":"https://randomuser.me/api/portraits/med/women/45.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/45.jpg"},"nat":"GB"}],"info":{"seed":"98f4f4a344470fbd","results":1,"page":1,"version":"1.2"}}
    

    You can further convert the result to Java object using a technique called JsInterop DTOs. If you are interested, please find some information here: https://stackoverflow.com/a/50565283/5394086 .

    Not recommended approach

    If you sadly prefer to use the old GWT, so <= 2.7, then I think you can search for some examples on Github using similar search query, but for this legacy com.google.gwt.xhr.client.XMLHttpRequest. I this case I would also suggest you to not do stuff so low level, but use a library like https://github.com/reinert/requestor (which is unfortunately discontinued and development has stopped on GWT 2.7, but for this GWT version it is probably the best choice). But again please do not go this way and use GWT >= 2.8.2 with Elemental2/JsInterop approach instead.