Your enterprise data may be spread across a number of different systems. With our newly improved service-backed records, you can easily bring all of your data together and use it in one place.
This tutorial pertains to service-backed records without sync enabled. To learn how to use a web service as the record type data source with sync enabled, see Use a web service with sync enabled.
This tutorial guides you through the steps for creating a service-backed record that powers a fictional SpaceX Launch application. Service-backed records differ from other kinds of record types in that they use web services as their data source. We'll use the r/SpaceX API to configure an service-backed record to power a test application designed to manage space launch data.
Most APIs require authentication. The r/SpaceX API is a freely available, open source API that uses JSON, which doesn't require authentication. This makes it ideal for this tutorial because we don't need verification credentials in order to connect to it. Specifically, we will use the Launches API, which is resourced within the r/SpaceX API and supports paging, searching, and filtering.
You’ll learn how to use a web service integration to create a record type. Although this tutorial focuses more on the specifics of configuring the record type's data source and record list view, you'll also have an opportunity to create other Appian design objects required to build the record type and SpaceX Launch application.
You'll create the following design objects:
After you complete this tutorial, you will understand how to use your own data or API to create a service-backed record. The final configurations for your Appian records will change based on your field names and data types.
To successfully complete this tutorial, you must first complete the Application Building Tutorial. We'll use some of the objects created in the application tutorial to set up our SpaceX Launch application. You also need to have a basic familiarity with Appian Interfaces and a basic understanding of APIs and how to use them. To gain practice designing Appian interfaces, walk through the Interface Tutorial and Process-Backed and Entity-Backed Record Tutorial.
Before we create the record type, we need to set up our application and user groups. We'll also need to create a Custom Data Type (CDT) that will define the structure and organization of the data for our record type.
Let's start by creating our SpaceX Launch application and a new user group. We'll leverage the AT Administrators user group created in the Application Building Tutorial as the parent group in our application.
Let's begin:
SpaceX Launch
in the Name field.Container for components of the SpaceX Launch application.
in the Description field.SpaceX Managers
in the Name field.Manager group for the Launch application.
in the Description field.Now we're ready to create our CDTs.
We need to define a custom data type with fields that match the expected integration response. These CDT fields will become the record fields that are available for use in our record list, record views, and record actions.
For this tutorial, we'll actually need to create two data types. Our main data type, SpaceX_Launch
, will define the data related to a specific launch. However, since our response is returning nested data about the rocket that was used in the launch, we also need to create a child CDT called SpaceX_Rocket
to represent it.
When creating the CDTs, follow the field order provided in the steps below. This will ensure the columns in your record list view match the order presented in this tutorial.
First we'll create the SpaceX_Rocket
data type:
:launch
to the end of the default namespace.SpaceX_Rocket
in the Name field.This custom data type defines the data fields associated with each rocket.
in the Description field.SpaceX_Rocket
data type will open in a new tab.Click Save.
Now let's create the SpaceX_Launch
data type:
:launch
to the end of the default namespace.SpaceX_Launch
.This custom data type defines the data fields associated with each launch.
.SpaceX_Launch
data type will open in a new tab.Click Save.
Now let's create and configure our new record type.
We will create and configure the record type in steps. We'll start with creating the data source objects, followed by setting up filters and configuring the integrations and expressions, and finally creating the record list view and record type's summary view.
To begin:
SpaceX Launch
. SpaceX Launches
will automatically populate in the Plural Name field.Record type for the SpaceX Launch application.
.SpaceX Managers
group and select Administrators as the permission level.SpaceX Launch
record type will open in a new tab.Before we can configure the integration objects, expression rules, and rule inputs needed to configure our record type, we need to select a data source for the record type.
When the SpaceX Launch record type opens in a new tab, the Data Model page opens by default. From this page, we'll select our data source and configure the record type.
Now, we'll set up an HTTP connected system for the r/SpaceX API and the expression rule that calls that integration. This will allow us to use an integration to call the external data into the record type. The configuration wizard will guide us through the process of creating the Appian design objects you need to configure the record data source.
To create an HTTP connected system:
r/SpaceX API
.An API that returns data about SpaceX launches.
.https://api.spacexdata.com/v3/
.None
since this is an unauthenticated API.Click Create.
Now we'll create an integration that connects to the r/SpaceX API
connected system and calls the external data for the record type.
SpaceX_getAllLaunches
.The integration that calls in data for the record data source
.SpaceX Rules
.This folder con expression rules, interfaces, and integrations for the SpaceX Launch applications
.SpaceX Rules
. This will allow you to select the SpaceX Rules folder we just created.We still need to configure the path and query parameters for the record data source integration, which we'll do in Configure the integration path and Configure query parameters for the integration.
After we create the integration for the record data source, the configuration wizard automatically defines the property fields for our expression rule. The record data source expression connects the integration to the record type, calls the integration, and transforms it into a DataSubset.
From the CREATE EXPRESSION RULE step, verify that the following information is automatically populated in each field below:
SpaceX_getAllLaunches_recordDataSource
The Record Data Source for the SpaceX Launch Record Type.
SpaceX Launch
SpaceX Rules
We still need to use SAIL to build the Record Data Source expression, which we'll do in Build the record data source expression rule .
Click NEXT to continue on to configuring rule inputs.
In the next step, we'll configure the integration to handle paging, searching, and filtering. The configuration wizard takes care of most of this for you by automatically enabling and mapping the rule inputs that control paging and searching to the record type. We'll add rule inputs to enable filtering by launch year, launch success, and flight number.
pagingInfo
of type PagingInfosearchText
of type Textlaunch_year
of type Textlaunch_success
of type Booleanflight_number
of type IntegerSpaceX_source_getAllLaunches_recordDataSource
. Click Search to see this automatically selected.SpaceX_Launch
CDT that we created earlier.Now it's time to configure the integration path, which allows the integration to populate the record list and return a list of the objects that will map to the Data Type we selected for the record type. We'll use the launches
endpoint to return an array of SpaceX launches. The rule inputs for this integration will be passed into the corresponding expression rule for the record data source.
In Relative Path, enter launches
. This will be appended to the Base URL of the connected system to form a URL of https://api.spacexdata.com/v3/launches
.
Click TEST REQUEST. This should return a success message:
Next, we'll configure the integration's offset
, limit
, sort
, and order
query parameters to enable paging and the rocket_name
parameter to enable search.
Paging is often the most complicated parameter to configure. This is because APIs don't understand the PagingInfo type, and different APIs handle paging in different ways. See the r/SpaceX API documentation for details on their pagination parameters.
We'll also configure the launch_year
and launch_success
parameters to enable filtering by launch year and launch success. All of these query parameters have dynamic values, and should be configured as expressions. We will populate their values using the rule inputs we previously created.
Let's begin:
ri!pagingInfo.startIndex - 1
as the parameter value.ri!pagingInfo.batchSize
as the parameter value.index(ri!pagingInfo.sort, "field", null)
as the parameter value.if(index(ri!pagingInfo.sort, "ascending", null), "asc", "desc")
as the parameter value.ri!searchText
as the parameter value.ri!launch_year
as the parameter value.Add the launch_success parameter to enable filtering by launch success and use the expression editor to enter ri!launch_success
as the parameter value.
ri!searchText and any rule inputs being used for filtering can have null values. However, a configured service-backed record will never have a null value for startIndex or batchSize. Therefore, test values should be set such that ri!pagingInfo.startIndex and ri!pagingInfo.batchSize are not null.
Now we'll use SAIL to build an expression rule for our record data source. This expression rule will transform the integration response into a DataSubset for the record list view. The rule inputs for this expression rule are taken from the record data source's integration rule inputs.
We've made this process easy for you by providing a SAIL template in the expression rule object. To build the expression rule, simply follow the instructions and comments provided in the template along with the steps below. Note that some sections of the SAIL code are preconfigured for you. As you go through each step in the template, verify that the preconfigured code matches the configurations defined in the steps below.
Let's begin:
a!localVariables
to call the integration with the following rule inputs.
pagingInfo
parameter value to ri!pagingInfo
searchText
parameter value to ri!searchText
launch_year
parameter value to ri!launch_year
launch_success
parameter value to ri!launch_success
See the SAIL code below.
sail
a!localVariables(local!integrationResponse: rule!SpaceX_getAllLaunches(
pagingInfo: ri!pagingInfo,
searchText: ri!searchText,
launch_year: ri!launch_year,
launch_success: ri!launch_success,
flight_number: ri!flight_number
),
1
and a batch size of 5
as expected.
From the Ad Hoc Test view, enter a!pagingInfo(1,5)
in the expression value field for the pagingInfo
rule input.
Click TEST RULE. Your results should look similar to the test results shown below.
After successfully calling the integration, comment out local!integrationResponse
(line 15) in the expression rule.
1
/*local!integrationResponse*/
a!dataSubset
to configure the expression rule to transform the integration result into a DataSubset. First, verify the preconfigured pagingInfo
parameter values match the configurations below.
startIndex
parameter value to ri!pagingInfo.startIndex
batchSize
parameter value to ri!pagingInfo.batchSize
Set the sort
parameter value to ri!pagingInfo.sort
1
2
3
4
a!dataSubset(
startIndex: ri!pagingInfo.startIndex,
batchSize: ri!pagingInfo.batchSize,
sort: ri!pagingInfo.sort,
data
parameter value to local!integrationResponse.result.body
to use the list of launches for the record list data.Use the if()
function to configure the identifiers
parameter value to return any flights from the DataSubset by the flight_number
identifier as shown below.
1
2
3
4
identifiers: if(tointeger(local!integrationResponse.result.headers.'Spacex-Api-Count') > 0,
index(local!integrationResponse.result.body, "flight_number", null),
{}
),
Next, use the tointeger()
function to configure the totalCount
parameter returned by the integration response as shown below.
1
totalCount: tointeger(local!integrationResponse.result.headers.'Spacex-Api-Count')
)
(line 39)Check your code with the expression below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
a!localVariables(
/* 1. First, configure the integration object to return successfully */
local!integrationResponse: rule!SpaceX_getAllLaunches(
pagingInfo: ri!pagingInfo,
searchText: ri!searchText,
launch_year: ri!launch_year,
launch_success: ri!launch_success,
flight_number: ri!flight_number
),
/* 2. Then, ensure that you can call the integration from this expression rule */
/*local!integrationResponse*/
/* 3. Once you’ve called the integration successfully, comment out the line above this */
/* 4. Finally, use the successful response to construct the DataSubset below */
/*Transform the integration result into a DataSubset*/
a!dataSubset(
startIndex: ri!pagingInfo.startIndex,
batchSize: ri!pagingInfo.batchSize,
sort: ri!pagingInfo.sort,
/*Use the list of launches for the record list data*/
data: local!integrationResponse.result.body,
/*If any launches were returned, use the flight number as the identifier*/
identifiers: if(
tointeger(local!integrationResponse.result.headers.'Spacex-Api-Count') > 0,
local!integrationResponse.result.body.flight_number,
{}
),
/*Use the totalCount returned by the response*/
totalCount: tointeger(local!integrationResponse.result.headers.'Spacex-Api-Count'),
)
)
Now that we've configured the record data source, let's verify that the data returned for your record data source expression matches the fields in our data type.
You can access the Test Record Source box from the Source page of your record type to test both the record data source expression and the single record source expression. You should test your expression rules after completing any of the following testable increments.
Now let's verify that the data results returned for our record data source expression matches the DataSubset we expect for the record type.
Verify the column titles match the fields in SpaceX_Launch CDT and the record data returns as expected.
Now that we've configured our record data source, we can create our single record source. First, we will create an integration, and then we will create an expression to wrap it.
The second integration we build will populate the record views. This integration should return a single object that will map to the data type for the record type.
We will be using the launches/{{flight_number}}
endpoint to return data for a single SpaceX launch.
Let's begin:
From the record type Source page, click Create Single Record Source. This will open the single record source configuration wizard.
By default, the Create a new integration option is selected.
r/SpaceX API
.SpaceX_getOneLaunch
.The single record source integration for the SpaceX Launch application.
.SpaceX Rules
folder.We still need to configure the path and rule input for the record data source integration and build the expression, which we'll do in Configure the single record source integration and Build the single record source expression rule.
Now, let's configure the integration to fetch data for a single record view by an id
rule input. Appian will automatically create the id
rule input we need to return data for a specific launch record.
Let's begin:
id
from type Any Type
to type Number (Integer)
.
1
.Edit the Relative Path as an expression and set it to "launches/"&ri!id
. This will be appended to the Base URL of the connected system to form a URL of "https://api.spacexdata.com/v3/launches/1
, given our test value of 1
for ri!id.
Click TEST REQUEST. This allows us to run some tests to ensure our integration is behaving as expected. Given our test value of 1
for ri!id, this should return a success message:
Now that we've configured an integration to back our record view, we need to create an expression to wrap it. This expression will act as the glue between the integration and the record type, by calling the integration and transforming it into an Appian dictionary.
Like we did for the record data source expression, we'll use SAIL to build an expression for our single record source.
Let's begin:
Review the SAIL code and verify that it uses a!localVariables to call the SpaceX_getOneLaunch
integration.
1
2
3
4
5
a!localVariables(
local!integrationResponse: rule!SpaceX_getOneLaunch1(
id: ri!id
),
Configure the expression rule to to call the integration and return a dictionary.
1
rule!SpaceX_GetOneLaunch(id: ri!id).result.body
id
from type Any Type
to type Number (Integer)
.
1
.Now let's enhance our record list by configuring our user filters.
The user filters we added earlier to our expression are already made for us in the User Filters page of the record type, but we still need to configure them.
To edit a User Filter:
1
2
3
4
a!recordFilterChoices(
choiceLabels: {2015,2016,2017,2018,2019,2020},
choiceValues: {2015,2016,2017,2018,2019,2020}
)
Test your filter configuration by selecting 2015 in the LAUNCH YEAR dropdown.
Once again, at this point we can navigate to Tempo to verify that your new filter is interacting with your record list as expected. Incremental testing is a major key to success for serviced-backed records.
For more practice, configure a second User Filter for the launch_success
parameter using the ri!launch_success rule input
Now, let's use the Test Record Source box to verify that the data results returned for our Single Record Source expression returns data
To verify the Single Record Source expression, simply select the Single Record Source view, enter 1
in the Record Identifier field, and click TEST.
Now let's populate our record list with more meaningful data.
No launches exist with this criteria.
in the Empty Grid Message field.5
. This controls the batchSize that is passed into the Paging Info input for your single record source.Mission Name
link. The grid configuration pane will show details about that column.
mission_name
. This controls the sortInfo
that is passed into pagingInfo input for your record data source.Click SAVE CHANGES.
You should end up with a list view that looks like this:
The last step of this tutorial is to create the summary view. Structurally, a summary view for a service-backed record is no different from a summary view for any other record type. What may be different, however, is how you acquire the data.
SpaceX_LaunchSummaryView
in the Name field.
and choose a rule folder to save into.
The Summary View interface for the SpaceX Launch application.
.SpaceX Rules
as the Save In folder.launch
and set the data type to SpaceX_Launch.Copy the expression below and paste in the interface definition.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
a!boxLayout(
label: "Flight #"&ri!launch.flight_number&" Launch Info",
contents: {
a!sideBySideLayout(
items: {
a!sideBySideItem(
item: a!textField(
label: "Date",
labelPosition: "ADJACENT",
value: ri!launch.launch_date_utc,
readOnly: true
)
),
a!sideBySideItem(
item: a!textField(
label: "Name",
labelPosition: "ADJACENT",
value: ri!launch.rocket.rocket_name,
readOnly: true
)
),
a!sideBySideItem(
item: a!richTextDisplayField(
label: "Success",
labelPosition: "ADJACENT",
value: a!richTextIcon(
icon:
if(
ri!launch.launch_success,
"check-circle",
"times-circle"
),
color:
if(
ri!launch.launch_success,
"POSITIVE",
"NEGATIVE"
)
)
)
)
}
),
a!textField(
label: "Details",
labelPosition: "ADJACENT",
value: ri!launch.details,
showWhen: not(isnull(ri!launch.details)),
readOnly: true
)
},
iscollapsible: true
)
The last steps are to get the record's title and summary view configured.
rv!record[recordType!SpaceX Launch.fields.mission_name]
to give each record the title of launch mission.
rv!identifier
. Your expression should look something like the example below.
1
2
3
4
5
6
7
8
9
10
11
12
13
rule!SpaceX_LaunchSummaryView(
launch:
'type!{urn:com:appian:types:launch}SpaceX_Launch'(
id: rv!identifier,
flight_number: rv!record[recordType!SpaceX Launch.fields.flight_number],
mission_name: rv!record[recordType!SpaceX Launch.fields.mission_name],
launch_year: rv!record[recordType!SpaceX Launch.fields.launch_year],
launch_date_utc: rv!record[recordType!SpaceX Launch.fields.launch_date_utc],
rocket: rv!record[recordType!SpaceX Launch.fields.rocket],
launch_success: rv!record[recordType!SpaceX Launch.fields.launch_success],
details: rv!record[recordType!SpaceX Launch.fields.details]
)
)
Congratulations! Your record is complete. It should look something like:
If you want to use a record picker with your service-backed record, it should work as expected, without the need to change your record definition. But, in case something is not working as desired, here are a few notes on how the record picker works and how you can tweak your record design to optimize for a record picker.
If this picker does not meet your needs, use a custom picker.
For more information about records, see Appian Records.