Quickly Connect, Display, and Transform Network API Data In Your Cross Platform App using Flutter Markup Language

Isaac Olajos
10 min readFeb 1, 2023

--

Today we are going to look at connecting to and traversing data in your Flutter Markup Language app! Although there are many supported Datasources, we are going to look at the REST api Datasource GET, how to bind to and traverse data, passing data to UI widgets to automatically create views such as lists and tables, and transforming data using TRANSFORM widgets.

If you are unfamiliar with FML, it’s use cases, or would like to learn more, you can check out our YouTube channel, visit the GitHub wiki, or see live examples on fml.dev.

What we will cover:

  • Connecting to a GET Datasource Widget.
  • Binding and Traversing JSON and XML data.
  • Easily creating UI from your Datasource using the data UI LIST Widget.
  • Manipulating database calls using url attributes.
  • Transforming live data using TRANSFORM Widgets.

Although this list covers a very small portion of the possibilities and Datasources available in FML, it should give you a broad understanding of the general usage and functions of Datasources in Flutter Markup Language.

For deep dives on automatically posting forms, creating posting bodies automatically and manually, and more information on Datasources and how to quickly build applications using FML, follow us on Medium or YouTube to catch new articles and videos weekly!

Lets get started!

Setting up a GET Datasource and Traversing Data Structures

To begin, you will need your FML app up and running on any device you choose. If you have not done this, check out our Quickstart articles using NGROK or using XAMPP, or our Quickstart Guide.

For this example, we are going to use the free api “https://randomuser.me/api/”. This API’s return body is in JSON format, but FML supports both JSON and XML structure for databinding. The Datasources will detect which structure the body is in and the process will be the same.

Lets take a look at the data returned from the randomuser.me get call:

{
"results":[
{
"gender":"male",
"name":{
"title":"Mr",
"first":"Timothee",
"last":"Thomas"
},
"location":{
"street":{
"number":1975,
"name":"Rue des Cuirassiers"
},
"city":"Boulogne-Billancourt",
"state":"Lozère",
"country":"France",
"postcode":46879,
"coordinates":{
"latitude":"-18.6054",
"longitude":"-47.9350"
},
"timezone":{
"offset":"+5:00",
"description":"Ekaterinburg, Islamabad, Karachi, Tashkent"
}
},
"email":"timothee.thomas@example.com",
"login":{
"uuid":"ffa3b296-b068-4fa5-8bd3-235a71cd0906",
"username":"ticklishduck262",
"password":"pooppoop",
"salt":"UcyG7Qvb",
"md5":"d696229eaeac062ae18df1d9b9bee068",
"sha1":"100e1b68aa669be8d1d993d8bc99f63e87984fec",
"sha256":"c29656f69ab6cbcb5371ae5f4eb8ed124696b8712a36980e887186a874ed4338"
},
"dob":{
"date":"1956-01-25T07:58:50.982Z",
"age":66
},
"registered":{
"date":"2008-08-18T07:28:44.413Z",
"age":14
},
"phone":"03-07-80-50-47",
"cell":"06-21-38-07-41",
"id":{
"name":"INSEE",
"value":"1560050243529 65"
},
"picture":{
"large":"https://randomuser.me/api/portraits/men/65.jpg",
"medium":"https://randomuser.me/api/portraits/med/men/65.jpg",
"thumbnail":"https://randomuser.me/api/portraits/thumb/men/65.jpg"
},
"nat":"FR"
}
],
"info":{
"seed":"040edff4e05cdca9",
"results":1,
"page":1,
"version":"1.4"
}
}

As you can see, the repeated element would normally be within “results”, and there is the “info” element at the same level as results. Knowing the structure of your data is important to set up Databindings.

Setting Up and Binding to a GET Datasource Widget

First, lets open our template with the <FML> tags and create a GET widget. We will give the GET widget an id attribute and the url attribute containing our api call.

<FML>
<!--Set up an id and provide a url-->
<GET id="userdata" url="https://randomuser.me/api/"/>
</FML>

GET will accept a relative or absolute url, if the url is relative such as url=“/api”, the application will make the fully qualified domain call to the domain your FML app is hosted at.

Next, lets take a look at the outer two elements using a TEXT widget to bind to an attribute and the data from the GET widget. If you are unfamiliar with databinding, you can check out the databinding page in the wiki.

<FML>
<GET id="userdata" url="https://randomuser.me/api/"/>

<COL>
<!--Binding to the url attribute-->
<TEXT value="{userdata.url}" color="red"/>
<!--Binding to the data info and results-->
<TEXT value="{userdata.data.info}"/>
<TEXT value="{userdata.data.results}"/>
</COL>

</FML>

Remember, to bind to a widgets attribute, the structure is {id.attribute}, whereas data, being its own attribute, is {id.data.element}. Whenever {} are used, they signify a binding. In this case we will bind to results and info elements, as well as display the url attribute’s value on the GET widget.

Now, we see that the info data isn’t very useful for us, so lets create a root=“results” attribute on the GET widget to display only data within the results element.

<!--We add the root, this allows our bindings to start within the results element-->
<GET id="userdata" url="https://randomuser.me/api/" root="results"/>

This will allow the Datasource to start bindings at the “results” element rather than the outer most level of the data. Remember, if the desired root is multiple levels down, you will need to use dot notation from the outer most level of the data structure to specify the root, such as root=“results.name”.

Next, we can access the gender in the same way we did the results, keeping in mind that bindings start at the root results using the binding {userdata.data.gender}.

<FML>
<!--adding the root tag allows the binding to start at the root given-->
<GET id="userdata" url="https://randomuser.me/api/" root="results"/>

<COL>
<TEXT value="{userdata.url}" color="red"/>
<!--we grab the value from the gender element-->
<TEXT value="{userdata.data.gender}"/>
</COL>

</FML>

Traversing Data Structures with Databinding

Next, lets look at traversing this data. We can do so by using dot notation. Lets grab the value of the users street name using {userdata.data.location.street.name}. This simply traverses down the nested datastructure provided by the API.

<TEXT value="{userdata.url}" color="red"/>
<TEXT value="{userdata.data.gender}"/>
<!--we traverse the tree to grab the name of the street using dot notation-->
<TEXT value="{userdata.data.location.street.name}"/>

As you can see, we are able to access infinitely nested values within a data tree from both XML or JSON, using a root at any level.

Next, lets look at using the repeated elements to create a visual list UI.

Creating a LIST UI from a Datasource

First, lets get a few more users from the randomuser api by changing the url and grabbing the users first name rather than the gender.

<FML>
<!--Add results=4 as an attribute on the url to return more than a single result-->
<GET id="userdata" url="https://randomuser.me/api?results=4" root="results"/>

<COL>
<TEXT value="{userdata.url}" color="red" root="results"/>
<!--We grab the users first name for a more useful display-->
<TEXT value="{userdata.data.name.first}"/>
<TEXT value="{userdata.data.location.street.name}"/>
</COL>

</FML>

As you can see, even though there are multiple elements the binding will automatically select the first one when not given an index. We can select a specific item when not using a Data UI widget by using the element:Index notation at the end of our repeated element name. In this case, the element is called results, so we can remove the root, or append the index to the data keyword.

<FML>
<!--We remove the root to access the repeated elemt name to supply an index-->
<GET id="userdata" url="https://randomuser.me/api?results=4" root="results"/>

<COL>
<TEXT value="{userdata.url}" color="red"/>
<!--Grabs the 0th index of repeated item by default-->
<TEXT value="{userdata.data.name.first}"/>
<!--Grabs the 3rd index of root element, with no root this would be data.results:3...-->
<TEXT value="{userdata.data:3.location.street.name}"/>
</COL>

</FML>

Now, we can automatically display every element as its own UI element using a Data UI Widget. Lets remove the COL and its children and create a LIST. Supply the id of the datasource to the data=“” attribute in the LIST and create an item.

<FML>
<GET id="userdata" url="https://randomuser.me/api?results=4" root="results"/>
<!--We supply the id of the datasource to the list-->
<LIST data="userdata">
<ITEM>
</ITEM>
</LIST>
</FML>

Inside the item, lets create a BOX with a border and display a TEXT bound to name. When binding inside a data widget, no id prefix is needed if binding to the source passed to the data=“” attribute. This will bind to any data within the widgets scope.

<FML>
<GET id="userdata" url="https://randomuser.me/api?results=4" root="results"/>
<LIST data="userdata">
<ITEM>
<BOX border="all" bordercolor="black" height="80" width="100%">
<!--We bind to the data passed to the LIST using data. with no ID-->
<TEXT value="The name is: {data.name.first}"/>
</BOX>
</ITEM>
</LIST>
</FML>

As you can see, this instantly creates a scrollable list. You can use things like evals, events, attributes, and other UI widgets to dynamically change and update list items, make them interactive, and more!

Updating Datasource Calls Using URL Bindings

Now, lets manipulate the data by updating the url parameters using a SLIDER and databinding.

First, create a SLIDER with a value of 0 to 10, and assign it an initial value of 1.

<FML>
<GET id="userdata" url="https://randomuser.me/api?results=4" root="results"/>
<HEADER>
<!--we create a slider with a value-->
<SLIDER id="resultnum" color="green" minimum="1" maximum="10" divisions="8" value="1" width="300"/>
</HEADER>
<LIST data="userdata">
<ITEM>
<BOX border="all" bordercolor="black" height="80" width="100%">
<TEXT value="The name is: {data.name.first}"/>
</BOX>
</ITEM>
</LIST>
</FML>

Next, add the binding to the SLIDER as a replacement for the results= parameter in the api url.

<FML>
<!--We bind the value of the slider to the url attribute-->
<GET id="userdata" url="https://randomuser.me/api?results={resultnum}" root="results"/>
<HEADER>
<SLIDER id="resultnum" color="green" minimum="1" maximum="10" divisions="8" value="1" width="300"/>
</HEADER>
<LIST.../>
</FML>

As you can see, when we move the SLIDER, the GET call is automatically made, and the list rebuilds on success of the GET, reflecting the amount of results set by the SLIDER’s value. This automatic updating on url change can be altered using the autoexecute=“false” attribute on the Datasource and called using the <id>.start() event if desired.

Transforming Data Using TRANSFORM Widgets

The final piece of the Datasource overview we will look at is creating and binding to TRANSFORM widgets. In this case, we will use the FILTER and CALC Transforms, but there are many more available using Flutter Markup Language!

Transforms act as direct children of Datasources, and will take affect in whatever order the developer inserts them, returning the transformed data to the parent after each takes affect.

Using our list template from above, lets add a FILTER transform as a child of GET.

<GET id="userdata" url="https://randomuser.me/api?results={resultnum}" root="results">
<FILTER id="f1" filter="{data.gender} == 'male'"/>
</GET>

Next we will give the filter an evaluation in the filter=“” attribute. If this evaluation returns true, it will add that repeated element to the dataset to be bindindable. If false, it will be excluded from the dataset. The filter assumes the bindable field will be a name within the dataset, and can be traversed as usual using the dot notation. No id prefix is needed as the binding is within the brokers scope.

<GET id="userdata" url="https://randomuser.me/api?results={resultnum}" root="results">
<FILTER id="f1" filter="{data.gender} == 'male'"/>
</GET>

Now we can see when running the list, although we request 8 results, the filter excludes any where the gender field does not equal male.

If we include multiple transforms, they will take affect in order given. Lets add a CALC after the FILTER and have it add the maximum age off all of the fields in the male category to all of the datasets as a field called “maxage” under “dob”.

<GET id="userdata" url="https://randomuser.me/api?results={resultnum}" root="results">
<FILTER id="f1" filter="{data.gender} == 'male'"/>
<CALC id="f2" target="dob.maxage" operation="max" source="dob.age"/>
</GET>

Lets add some databindings in our list to display this data.

<LIST data="userdata">
<ITEM>
<BOX border="all" bordercolor="black" height="80" width="100%">

<!--Create a var to calculate the difference, this can also be done with a transform-->
<VAR id="difference" value="={data.dob.maxage}-{data.dob.age}"/>
<TEXT value="The name is: {data.name.first}"/>
<!--Display the difference-->
<TEXT value="I am {difference} years younger."/>

</BOX>
</ITEM>
</LIST>

And this is our UI:

Now, if we want access to all levels of data, or different sets of transforms, we can use the DATA widget to nest down. We assign the id of the parent Datasource to the url=“” of the DATA widget. We can also use the data widget separately and supply the id as the url in the same way. Now we can bind to the unfiltered GET data using userdata.data, or the filtered data using the DATA id filtereddata.data. We can even pass the url of the filtereddata to another DATA widget to nest transforms!

<GET id="userdata" url="https://randomuser.me/api?results={resultnum}" root="results">
<DATA id="filtereddata" url="userdata">
<FILTER id="f1" filter="{data.gender} == 'male'"/>
<CALC id="f2" target="dob.maxage" operation="max" source="dob.age"/>
</DATA>
</GET>

DATA widgets can take data from any Datasource, or widgets that supply data such as a SELECT.

And that’s it for the overview! As you can see at its most basic level, FML makes binding to and manipulating data from any source in any structure simple. To check out binding to Hardware Datasources such as NFC and CAMERA, and using DETECTOR widgets to bind to ML kit information such as barcodes, you can keep a lookout for the next article on hardware Datasource binding.

I hope you enjoyed this overview. If you have any questions about FML, Datasources, transforming data, binding to data, and more you can:

Thanks for reading!

--

--

Isaac Olajos

Health and Technology. Flutter Markup Language developer, Integrated Movement Training owner.