Access a REST Service

In addition to the XMLHttpRequest object, which QML supports by default, you can rely on the V-Play HttpRequest type to access REST APIs. It integrates DuperAgent, a QML clone of the fantastic SuperAgent library from VisionMedia.

 import VPlayApps 1.0
 import QtQuick 2.0

 App {
   // This signal handler is called when the app is created, like a constructor
   Component.onCompleted: {
     // show network activity indicator for ongoing HttpRequest without activation delay
     HttpNetworkActivityIndicator.activationDelay = 0

     // get IP via http request
     getIp()
   }

   NavigationStack {
     Page {
       title: "IP HttpRequest"
       rightBarItem: ActivityIndicatorBarItem {
         enabled: HttpNetworkActivityIndicator.enabled
         visible: enabled
       }

       AppText {
         id: ipText
         anchors.centerIn: parent
       }
     }
   }

   function getIp() {
     // create request
     HttpRequest.get("https://api.ipify.org?format=json")
     .then(function(res) {
       // The responseText looks like this {"ip":"xxx.xxx.xxx.xxx"}
       // it automatically gets parsed into a JSON object
       var responseJSON = res.body
       // Read the ip property of the response
       var ip = responseJSON.ip
       // Display the ip in the AppText item
       ipText.text = "IP: " + ip
     })
     .catch(function(err) {
       console.log("Error: "+err.message);
     });
   }
 }

If you prefer, you can also connect to REST services using the XMLHttpRequest object:

 import VPlayApps 1.0
 import QtQuick 2.0

 App {
   // This signal handler is called when the app is created, like a constructor
   Component.onCompleted: getIp()

   NavigationStack {
     Page {
       AppText {
         id: ipText
         anchors.centerIn: parent
       }
     }
   }

   function getIp() {
     // Create the XMLHttpRequest object
     var xhr = new XMLHttpRequest

     // Listen to the readyStateChanged signal
     xhr.onreadystatechange = function() {
       // If the state changed to DONE, we can parse the response
       if (xhr.readyState === XMLHttpRequest.DONE) {
         // The responseText looks like this {"ip":"xxx.xxx.xxx.xxx"}
         // Parse the responseText string to JSON format
         var responseJSON = JSON.parse(xhr.responseText)
         // Read the ip property of the response
         var ip = responseJSON.ip
         // Display the ip in the AppText item
         ipText.text = "IP: " + ip
       }
     }

     // Define the target of your request
     xhr.open("GET", "https://api.ipify.org?format=json")
     // Execute the request
     xhr.send()
   }
 }

There is an in-depth guide how to create a weather app that uses a weather REST service via XmlHttpRequest posted on our blog: How to Access REST Services with Qt and V-Play: Weather Service Example App

Promise API

You can also take advantage of promises similar to the Promises API in ES2017. This is how you can create a Promise in QML to handle the result of an HttpRequest:

 import VPlayApps 1.0
 import QtQuick 2.0

 App {
   Component.onCompleted: {

     var p = Promise.create(function(resolve, reject) {
       // handle asynchronous code here
       // e.g. with asynchronous HttpRequest
       HttpRequest
         .get("http://httpbin.org/get")
         .timeout(5000)
         .end(function (err, res) {
           if(res.ok)
             resolve(res.body)
           else
             reject(err.message)
         })
     });

     // execute promise and handle result
     p.then(function(value) {
        // success
       console.log("Value: "+JSON.stringify(value))
     }).catch(function(reason) {
       // failure
       console.log("Error: "+reason)
     });

   }
 }

Promises are a convenient way to handle asynchronous aspects of your application. Each Promise wraps your asynchronous code, so you can handle the result in a flexible way.

For example, it is also possible to concurrently execute several promises and go on with your code if all promises resolved without issue:

 import VPlayApps 1.0
 import QtQuick 2.0

 App {
   Component.onCompleted: {
     var p1 = Promise.resolve(3);
     var p2 = 1337;
     var p3 = HttpRequest
             .get("http://httpbin.org/get")
             .then(function(resp) {
                 return resp.body;
             });

     var p4 = Promise.all([p1, p2, p3]);

     p4.then(function(values) {
         console.log(values[0]); // 3
         console.log(values[1]); // 1337
         console.log(values[2]); // resp.body
     });
   }
 }

If one of the original promises fail, the returned promise will be rejected with the same reason.

Multiple HttpRequests with Promise, Caching and Activity Indicator

The following example combines multiple http requests with a promise, caching and an activity indicator:

 import VPlayApps 1.0
 import QtQuick 2.0

 App {

   Component.onCompleted: {
     // remove activation delay to immediately show the indicator for requests
     // otherwise, requests that take less than the default 150 ms won't trigger the indicator
     HttpNetworkActivityIndicator.activationDelay = 0

     // configure caching
     HttpRequest.config({
       cache: { maxSize: 20000 } // max size of 200000 bytes
     })
   }

   NavigationStack {
     Page {
       id: myPage
       title: "HttpRequest Example"
       rightBarItem: ActivityIndicatorBarItem {
         animating: HttpNetworkActivityIndicator.enabled
         visible: animating
       }

       // HttpNetworkActivityIndicator is not supported with Promises
       // this example thus uses a custom activity indicator handling
       property bool promisePending: false

       // function to send all requests and handle the result
       function sendAllRequests() {
         // trigger first request
         var p1 = HttpRequest
           .get("https://jsonplaceholder.typicode.com/todos/1")
           .cacheSave(false) // do not save response of first request to cache
           .cacheLoad(HttpCacheControl.AlwaysNetwork) // always load from network
           .then(function(res){ return res.body; });

         // trigger second request
         var p2 = HttpRequest
           .get("https://jsonplaceholder.typicode.com/posts/1")
           .timeout(5000)
           .cacheLoad(HttpCacheControl.PreferCache) // use cache if possible, otherwise load from network
           .then(function(res){ return res.body; });

         // create promise to check success of both requests
         var allRequests = Promise.all([p1, p2])

         // handle promise result
         allRequests.then(function(values) {
           console.log("Both requests finished: "+JSON.stringify(values))
         }).catch(function (err) {
           console.log("Error: "+err)
         })
       }

       AppButton {
         text: "Send Get Requests"
         anchors.centerIn: parent
         onClicked: myPage.sendAllRequests()
       }
     }
   }
 }

How do I write asynchronous code?

As V-Play relies on QML and Javascript, updates to the UI are already handled in a highly asynchronous and event-driven way. You weave-in your Javascript code as part of signal handlers that execute when certain events or user interactions happen. The QML rendering engine is highly optimized, so you do not need to worry about blocking the UI when adding your view logic.

Communication with your application backend is also easy, as you can use the HttpRequest Element asynchronously. The following example fetches a JSON response containing the URL to an image. The request happens asynchronously. The returned URL is then set as the AppImage source, which is able to asynchronously load an image from an URL:

 import VPlayApps 1.0
 import QtQuick 2.0

 App {

   property string serverUrl: "https://jsonplaceholder.typicode.com/photos/1"
   property var jsonData: undefined

   // handler function to be executed when the App Item is fully created, starts web requests
   Component.onCompleted: {
     // the 3rd parameter of open(...) is the asynchronous flag
     var request = HttpRequest
       .get(serverUrl)
       .then(function(res) {
         jsonData = res.body // keep JSON result
       })
       .catch(function(err) {
         console.log(err.message)
         console.log(err.response)
       });
   }

   Page {

     // just some spinning icon to show asynchronous loading of image
     Icon {
       anchors.centerIn: parent
       icon: IconType.refresh
       NumberAnimation on rotation {
         loops: Animation.Infinite
         from: 0
         to: 360
         duration: 1000
       }
     }

     AppImage {
       // expression for source relies on the jsonData property (property binding!)
       // the REST api returns the web url to an image, which we can set directly to load the image
       source: jsonData !== undefined ? jsonData.url : ""
       anchors.fill: parent
       fillMode: AppImage.PreserveAspectFit
       // additionally you can make the image loading itself asynchronous
       // this is recommended for images loaded from web source
       asynchronous: true
     }
   }
 }

After request completion, the result is stored to the jsonData property. The expression for the image source relies on the property, so the AppImage will automatically update and show the image as soon as the data arrives - nothing more to do.

More Frequently Asked Development Questions

Find more examples for frequently asked development questions and important concepts in the following guides:

Voted #1 for:

  • Easiest to learn
  • Most time saving
  • Best support

Develop Cross-Platform Apps and Games 50% Faster!

  • Voted the best supported, most time-saving and easiest to learn cross-platform development tool
  • Based on the Qt framework, with native performance and appearance on all platforms including iOS and Android
  • Offers a variety of plugins to monetize, analyze and engage users
FREE!
create apps
create games
cross platform
native performance
3rd party services
game network
multiplayer
level editor
easiest to learn
biggest time saving
best support