Tutorial GET Request to an External API Service - AppDaddy-Software-Solutions-Inc/framework-markup-language GitHub Wiki
In this tutorial we will be integrating an open api (🙌 thanks to ageify.io) to perform a HTTP GET request using FML which will guess a persons age based on their name.
- Input that a user can type the name of a person
- Button that triggers a call to the api endpoint and clears the input
- A GET HTTP datasource with the name as a parameter
- Notification of responses with failure handling
- Simple Layout and Stylization
- GET Requests
- Data Binding from an Input and a Datasource
- Events to fire the GET datasource, clear the input and toast() the result from the API
- Common Evaluation statements
As always we start by setting up our template lets give our template a title and set linkable=true
which allows direct linking when the application is setup as a single page application.
We have also created the functional and graphical skeletons for the template adding a <GET>
datasource and a <BOX>
widget. The former of which we have given a few common layout attributes to, ensuring the box is the size of the screen and that its children are centered.
<FML title="Tutorial: GET Request to an External API Service" linkable="true">
<GET>
</GET>
<BOX width="100%" height="100%" center="true">
</BOX>
</FML>
We need a button and an input. Lets put them inside a row within the box we created earlier.
We're going to use a <BOX layout="row">
instead of a <ROW>
because we plan on stylizing this with a color
from our theme.
<BOX width="300" height="110" layout="row" center="true" color="{THEME.primarycontainer}">
<INPUT id="name" />
<BTN onclick="" label="Get Age" />
</BOX>
Our API is going to reach out to a public service which takes in a name as a parameter. We are setting autoexecute="false"
because GET
datasources will automatically execute when a template is opened and we want ours to be triggered only by a button. When the call comes back we want to toast the user the result, to the onsuccess
we add the event toast
with some databound text and a display time of 3 seconds. In this instance we don't want to send any headers with the call so we add an empty HEADER
element child.
When using the response of a datasource you reference the id getage.
and then data.
followed by the response field, in this case age
.
<GET id="getage" url="https://api.agify.io/?name={name}" autoexecute="false"
onsuccess="toast('Name: {name} - Estimated Age: {getage.data.age}', 3)">
<HEADER />
</GET>
We also need to wire our button up to call the getage datasource, we can do this by adding a start
event to the button's onclick
attribute.
<BTN onclick="getage.start()" label="Get Age" />
The API has a few edge cases we should cover, for example if a name does not have an estimated age the API still returns a 200 OK but with an empty age
field, or if the API returns a non 200 OK code (note: you can see what exact codes are returned with getage.statuscode
).
Lets start by adding an onfail
attribute and a toast event for when the request returns a non 200 OK and then lets extend our onsuccess
event with an evaluation checking if the getage.data.age
bindable field is null or empty (noe) before toasting the appropriate message.
<GET id="getage" url="https://api.agify.io/?name={name}" autoexecute="false"
onsuccess="noe({getage.data.age}) ? toast('Undetermined Age', 2) : toast('Name: {name} - Estimated Age: {getage.data.age}', 3)"
onfail="toast('Something went wrong')">
<HEADER />
</GET>
Functionally this works but lets make it look better by implementing a design and some small user experience finishing touches.
On our inner BOX
lets make it look more like a card with a little elevation
elevation="2" shadowcolor="#11000000" shadowx="1" shadowy="1"
Our input isn't very intuitive and could use some styling so we will add a hint, set a color/width and remove the border
hint="Enter a name" color="{THEME.onprimary}" width="180" border="none"
Now that our input has a clear description of what it requires from the user it would be nice to just have a simple icon button that calls our GET
request by removing the label and adding an ICON
widget child. Lets also make sure the button is not enabled until the user has input a value and finally we will use event chaining to clear the input automatically after calling the request by setting the input to an empty string.
<BTN enabled="=!noe({name})" onclick="getage.start();name.set('')" radius="0" width="30">
<ICON icon="send" color="{THEME.onprimary}" size="38" />
</BTN>
We have created a working interface which uses a GET request to pass a user input and receive a response from the server to display to the user.
Click to View the Finished Template File
<!-- https://fml.dev/#/assets/templates/tutorial/get-request-to-an-external-api-service.xml -->
<FML title="Tutorial: GET Request to an External API Service" linkable="true">
<GET id="getage" url="https://api.agify.io/?name={name}" autoexecute="false"
onsuccess="noe({getage.data.age}) ? toast('Undetermined Age', 2) : toast('Name: {name} - Estimated Age: {getage.data.age}', 3)"
onfail="toast('Something went wrong')">
<HEADER />
</GET>
<BOX width="100%" height="100%" center="true">
<BOX width="300" height="110" layout="row" center="true" color="{THEME.primarycontainer}" elevation="2" shadowcolor="#11000000" shadowx="1" shadowy="1">
<INPUT id="name" hint="Enter a name" color="{THEME.onprimary}" width="180" border="none" />
<BTN enabled="=!noe({name})" onclick="getage.start();name.set('')" radius="0" width="30">
<ICON icon="send" color="{THEME.onprimary}" size="38" />
</BTN>
</BOX>
</BOX>
</FML>
This tutorial has utilized many core functionalities within FML to accomplish the outcome.
- GET datasource
- Multiple Events:
- toast()
- start()
- set()
- Evaluations using:
- noe()
- ternary statements
- Databinding:
- Global theme values
- INPUT widget value
- GET datasource response data
- Widgets:
- BOX
- INPUT
- BUTTON
- ICON
- Styling and Layout