Declaration of VAR

and some other stuff

XMLHttpRequest from QML

2018-06-09 14:44:02 +0200

2018-06-09 14:44:02 +0200 | Comments

XMLHttpRequest is a web standard (WHATWG/W3C, but better to read about it at MDN) for communication between JS-frontend and REST-backend.

And you can use it in QML.

Why use it in QML? So you could build a native and performant frontend clients for your backend, obviously! But if that’s not obvious enough for your, here’s a couple of points in favor of going this way instead of creating yet another web browser based monstrous client:

  • with Qt Quick/QML you can create a very rich GUI, effectively utilizing hardware acceleration for graphics;
  • to achieve something even remotely as fancy as Qt Quick/QML GUI, you’ll have to spend considerably more time with HTML/JS/CSS (and its performance will be shitty anyway);
  • QML-based applications are native applications with full-blown C++ capabilities under the hood, whether HTML-based silly thing is limited by a web browser’s sandbox;
  • I would like to see you trying to squeeze a web browser into a low-end embedded device.

So stop wanking around and forget about HTML/JS/CSS-based “applications”. HTML wasn’t created for that, you hipster twats - it’s a text markup language, capisce? Please, think about it when you’ll be considering yet another web browser based client for your application/service/whatever.

Okay, I’ve calmed down, let’s continue.

Here’s a JS-function that sends an XMLHttpRequest:

function request(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = (function(myxhr) {
        return function() {
            if(myxhr.readyState === 4) { callback(myxhr); }
        }
    })(xhr);

    xhr.open("GET", url);
    xhr.send();
}

And here’s how you can use it in QML:

...
onClicked: {
    request("http://example.org/api", function (o) {
        if (o.status === 200)
        {
            console.log(o.responseText);
        }
        else
        {
            console.log("Some error has occurred");
        }
    });
}
...

Now let’s test it with some real example. Say, we have a remote server with backend on C#/.NET and a QML-based frontend for it.

Make a directory for the backend and create a new .NET Core Web API project:

$ mkdir backend
$ cd backend
$ dotnet new webapi

Open Controllers/ValuesController.cs and change the Get method:

// GET api/values
[HttpGet]
public JsonResult Get()
{
    Dictionary<string, int> values = new Dictionary<string, int>()
    {
        { "Glasgow", 16 },
        { "London", 18 },
        { "Oslo", 23 },
        { "New York", 16 },
        { "San Francisco", 12 }
    };
    return Json(values);
}

Run it:

$ dotnet run
Hosting environment: Production
Content root path: /path/to/project/XMLHttpRequest/backend
Now listening on: http://0.0.0.0:5000
Application started. Press Ctrl+C to shut down.

And open http://0.0.0.0:5000/api/values in your browser:

Okay, it works. Now let’s modify our onClicked signal handler to process this JSON:

...
var jsn = JSON.parse(o.responseText);
for(var i in jsn)
{
    console.log(i + ": " + jsn[i]);
}
...

That would give the following console output:

qml: Glasgow: 16
qml: London: 18
qml: Oslo: 23
qml: New York: 16
qml: San Francisco: 12

Build the application and run it to see if it works. And using a HTTP debugging proxy, we can check if it really was an HTTP request to our backend:

But just a console output is boring, and with a bit of fantasy you can do something like this in less than half an hour:

Done - you have a frontend QML-application that fetches data from your backend using its REST API implemented with .NET Core Web API.

You can take a look at the complete source code of both backend and frontend projects in this repository.

…What are you saying, it’s not that much of a “rich and fancy GUI”? Well, then how about that:

Oh, and have I mentioned already that Qt-based applications are cross-platform?

By the way, this demo (Quick Forecast) was created 5 years ago (and actually doesn’t use XMLHttpRequest, but it might as well), and lots of new things were added to Qt Quick since then, so modern applications can have even richer and fancier GUI.

I really hope that world will see more lightweight and nice QML-based clients and less HTML-crippled snail-performant “applications”.

Just imagine how much faster and less memory greedy would be a native client for Slack, for example. In case you didn’t know - right now you’re literally running a copy of a web browser dedicated just for that. Add there your main browser, and then Skype, Wire, WhatsApp, Signal, Riot clients and you’ll get 7 (MOTHERFUCKING SEVEN) web browsers running in your system at the same time! Un-fucking-believable, what a time to be alive.