Expression-Backed Record Tutorial

The walk-through on this page will help you create your first expression-backed record. Expression-backed records differ from other types of record types in that they use web services as their source data.

Use the provided API to understand how the configurations work. Then, try it with your own data or API. Keep in mind, the final configurations will need to change to fit your data type's field names and types.

For this tutorial, you will be required to create several objects in your environment. If you do not have permissions to do so, speak with your system administrator. Also, you will need to create these object in an application. If you have a sandbox application available, you can build object in there. Similarly, you can follow the Application Building Tutorial and create object within that.

The content below assumes a basic familiarity with interfaces and focuses more on the specifics of configuring the data source and list view. Consider going through the Interface Tutorial and Process-Backed and Entity-Backed Record Tutorial. Additionally, Record Design and Create a Record Type pages provide more consideration and how-to examples related to record creation.

The content below also assumes that you have a basic familiarity with using APIs. Note that you will need to register for a freely available, open source API to complete this tutorial.

Setup

Before creating the record type, you will need to register for API access, create the integrations that will be the data source, and create a reference CDT.

Register for API Access

We will be using The Movie Database (DB) as our data source. Their API will let us retrieve movies released in the United State over the past two years.

Before using The Movie DB API, please read their terms of use before continuing.

  1. Sign-up for an account on The Movie DB.
  2. Once your account is verified, you will need to request an application API key following the directions on The Movie DB's getting started page.
    1. When signing up for an API Key, request a developer key.

Once your developer key has been approved, you should see your API Key in your user profile settings. Take note of the API Key (v3 auth) as we will be using it when we create our source integration object

Download Open API file

The Movie DB supports, among other standards, Open API. Download the OAS file (oas.json) found in their API documentation, which can be found in the header of the API page.

Create the source integration objects

Once you have your account, API key, and Open API file, we can now begin creating our integrations objects.

Create the Connected System

To create a connected system:

  1. Within an application in Appian Designer, click New and select Connected System.
  2. Since we are using an Open API document, select the OpenAPI Connected system.
  3. In the Create Connected System modal, give the connected system name
    • Optionally add a system logo and description
  4. In the OpenAPI/Swagger Document field, upload the oas.json file downloaded from the Movie DB API.
    • This file will be stored as an Appian Document. Name the document and save in an appropriate document folder.
    • After uploading the OpenAPI file, your modal will look something like this: ex_backed_record_connected_system.png
  5. From the OpenAPI file, the base url, authentication type, and HTTP parameter will be populated. In the value field Enter your API Key from your Movie DB account.
  6. Select Use in New Integration. A new modal will pop up allowing us to configure an integration for our source data. Steps to complete this will be in the next section.

Create Your First Integration

The first integration we build will populate the record's list view. We will be using the discover/movie operation to return an array of movies.

To create the integration to return movies:

ex_br_new_source_integration.png

  1. In the Create Integration modal select the GET /discover/movie Movie Discover option in the operation dropdown.
  2. Give the integration a name and choose a rule folder to save into.
    • Optionally add a description.
  3. Select Create. The integration will pop-up in a new tab.

Configuring Optional Parameters

Notice that the integration is pre-populated with all the necessary things to make an HTTP request to The Movie DB. If you'd like you can test the integration and see the result that come back from the integration.

ex_br_integration_default.png

Before we use this integration however, we will want to restrict the movies that come back to a more manageable data set. To do so, we will add several query parameters and a rule input to our integration.

  1. Add a new rule input called page with a data type of text.
  2. For each row in the table below click, Add Query Parameter and enter the parameter and value into each row in the query parameter
    • Edit values for all fields as an expression:
Parameter Value Notes
primary_release_date.gte text(today()-1095,"yyyy-mm-dd") Allows us to limit our results by showing only releases for the last three years. Using text function to pass in date in the format desired by the Movie DB
sort_by "revenue.desc" Sorting the movie by highest grossing
region "US" Limit to US movies only.
with_release_type "3|2" Returns only movies with a Theatrical or Theatrical (limited) release.
page ri!page Chooses which page to use.
  1. In the Automatic Output Parsing section, select Convert the JSON Response body to an Appian value.
  2. Test this request. you should see a batch of twenty movies sorted by highest gross revenue.
  3. Save the integration.

ex_br_integration_with_parameters.png

Create Your Second Integration

The second integration we will create will generate the record's view. When a user click on a link in the record list, this integration will call back to The Movie DB to get specific movie information.

  1. In your test application, click on the New dropdown, and select Integration.
    1. In the Create Integration modal, in the Connected System field find and select the Movie DB connected system.
    2. Select the GET /movie/{movie_id} Get Details option in the operation dropdown.
    3. Give the integration a name and choose a rule folder to save into. Optionally add a description.
    4. Click Create. The data type will open in a new tab.

    ex_br_second_integration.png

  2. In the Automatic Output Parsing section, select Convert the JSON Response body to an Appian value.
  3. Save the integration.

Create the Source Data Type

The last object we need to create is data type to map to our source expression. This will be used as our record fields.

  1. In your test application, click on the New dropdown, and select Data Type.
    1. In the Create Data Type modal create the data type from scratch.
    2. Append :EXAMPLE to the end of the default namespace.
    3. Name the data type movies. Optionally add a description
    4. Click Create. The data type will open in a new tab.
  2. For each item below, add a New Field, and give the name and data type specified below.
    • id (Number(Integer))
    • title (text)
    • overview (text)
    • release_date (text)
    • vote_count (Number(Integer))
    • vote_average (Number(Decimal))
    • popularity (Number(Decimal))
    • video (Boolean)
    • poster_path (Text)
    • original_title (Text)
    • genre_ids (Number(Integer))
      • Note The genre_ids field in the Movie DB is an array, however, to keep this example simple, we will only store the first genre published for each movie.
    • backdrop_path (text)
  3. Click Save.

When creating your CDT, follow the order above. This will ensure the columns in your list view matches what's are presented later in this example.

Now that we have all of our setup complete, let create and configure our new record type.

Create the Record Type

We will take a step-wise approach to configuring the record type, starting with source configuration, then setting up filters, followed by the record list, and finally the record type's summary view.

To begin:

  1. In your test application, click on the New dropdown, and select Record Type.
  2. Enter Movies in the Name and Plural Name of the records type.
  3. To give the Movie DB its proper attribution, enter the following attribution into the description This product uses the TMDb API but is not endorsed or certified by TMDb.
  4. Click Create. The record type will open in a new tab.

Configure the Data Source

Three things are needed when configuring a record type to accept expressions: a data type, a list view source expression, and a record view source expression. To access these fields, in the data section from the Source dropdown select Expression.

Once expression is selected you will see the fields to define the data source.

  1. In the Data Type field, select the Movie CDT created earlier.
  2. Copy the expression below and paste in the List View Source Expression. Replace the name of the integration rule below if needed.
    with( 
      local!result: rule!EXAMPLE_DiscoverMoveSourceExpression(
      page: floor(rsp!pagingInfo.startIndex / rsp!pagingInfo.batchSize) + 1,
      genres: local!genreIds
      ),
      local!movies: cast(
        'type!{urn:com:appian:types:EXAMPLE}movies?list',
        local!result.result.body.results
      ),
      a!dataSubset(
        startIndex: rsp!pagingInfo.startIndex,
        batchSize: 20,
        sort: rsp!pagingInfo.sort,
        totalCount: local!result.result.body.total_results,
        data: local!movies,
        identifiers: local!movies.id
      )
    )  
    
  3. Copy the expression below and paste in the Record View Source Expression. Replace the name of the integration rule below if needed.
    rule!GetMovieByID(rp!id).result.body
    
  4. Save the record type.

At this point, we have a fully functioning albeit limited record type. You can go to the record type to preview by clicking on the Record List URL.

images:expression_br_record_list.png

Before we add functionality to improve the usability of the records, let's review what we did. In our expression for the List View Source Expression we are creating a datasubset from our first integration. The one rule input we have, page gets the right page number by comparing the start index to the existing batch size.

The data subset is created using the a!datasubset() function. To create it, record source parameters (rsp!) are used to populate parameters of the data subset. Now that we have our source expressions configured, lets continue to make improvements to the record list by creating user filters, enabling search, and creating the record list.

Configure a User Filter

We are going to configure a user filter that will return a subset of movies based on genre. To do this, we will create another integration, setup the user filter expression, and finally update the List View Source Expression to accept user filter selections.

Create Genre Integration

  1. In your test application, click on the New dropdown, and select Integration.
  2. In the Create Integration modal, in the Connected System field find and select the Movie DB connected system.
  3. Select the GET /genre/movie/list Get Movies List option in the operation dropdown.
  4. Give the integration a name and choose a rule folder to save into.
    • Optionally add a description.
  5. Select Create. The integration will pop-up in a new tab.
  6. In the Automatic Output Parsing section of the integration, select Convert the JSON Response body to an Appian value.
  7. Click Save.

You can test this integration and see that it returns a series of movie genres.

Create the User Filter Expression

Once we have the genre movie

  1. In the User Filters field, copy the expression below and paste in the expression editor. Replace the name of the integration rule below if needed.
    with(
      local!genres: rule!EXAMPLE_GetMovieGenres().result.body.genres,
      a!facet(
     name: "Genres",
     allowMultipleSelections: false,
     options: {
       a!forEach(
         local!genres,
         a!facetOption(
           id: fv!index,
           name: fv!item.name,
           filter: a!queryFilter(
             field: "genre_ids",
             operator: "=",
             value: tointeger(fv!item.id)
           )
         )
       )
     }
      )
    )
    

This expression will create an array of filter options, which will compare the genre_id of a record to the value of the genre filter.

Update the List View Source Expression to Accept Filters

The last thing we need to do is update the List View Source Expression to include filter selection. To do this, we will add to new local variables, local!genreIndex and local!genreIds to the source expression. In addition to the source expression, we must also update our source expression integration.

  1. Open the Discover Movies integration.
  2. Add a new rule input called genres with a data type of integer.
  3. Add a query parameter and name it genere_ids. Set the value of genere_ids to ri!genres.
  4. Save the integration.

In the record type, update the List View Source Expression with the example expression below. The final expression will look something like this:

with(
  local!genreIndex: wherecontains("genre_ids", index(rsp!filters, "field", "")),
  local!genreIds: if(
    length(local!genreIndex) > 0,
    index(rsp!filters, "value", {}),
    {}
  ),
  local!result: rule!EXAMPLE_DiscoverMoveSourceExpression(
    page: floor(rsp!pagingInfo.startIndex / rsp!pagingInfo.batchSize) + 1,
    genres: local!genreIds
  ),
  local!movies: cast(
    'type!{urn:com:appian:types:EXAMPLE}movies?list',
    local!result.result.body.results
  ),
  a!dataSubset(
    startIndex: rsp!pagingInfo.startIndex,
    batchSize: 20,
    sort: rsp!pagingInfo.sort,
    totalCount: local!result.result.body.total_results,
    data: local!movies,
    identifiers: local!movies.id
  )
)

After saving the record type, you can check out the user filter operation on the movie's list view.

images:ex_br_user_filter.png

With this service we can search for keywords. To configure search results, we need to create an integration to the Movie DB's keyword search operation

Create Keyword Integration

  1. In your test application, click on the New dropdown, and select Integration.
  2. In the Create Integration modal, in the Connected System field find and select the Movie DB connected system.
  3. Select the GET /search/keyword Search Keywords option in the operation dropdown.
  4. Give the integration a name and choose a rule folder to save into.
    • Optionally add a description.
  5. Select Create. The integration will pop-up in a new tab.
  6. Add a new rule input called keyword with a data type of text.
  7. Add a query parameter and name it query. Set the value of query to ri!keyword.
  8. In the Automatic Output Parsing section of the integration, select Convert the JSON Response body to an Appian value.
  9. Click Save.

Update the List View Source Expression

Just as we updated the List View Source Expression for our user filter, we need to do the same for enabling search. In addition to the source expression, we must also update our source expression integration.

  1. Open the Discover Movies integration.
  2. Add a new rule input called keywords with a data type of text.
  3. Add a query parameter and name it with_keywords. Set the value of with_keywords to ri!keywords.
  4. Save the integration.

In the record type, update the Live View Source Expression with the example expression below. The final expression will look something like this:

with(
  local!search: rule!EXAMPLE_SearchMovieKeywords(rsp!searchText),
  local!genreIndex: wherecontains("genre_ids", index(rsp!filters, "field", "")),
  local!genreIds: if(
    length(local!genreIndex) > 0,
    index(rsp!filters, "value", {}),
    {}
  ),
  local!result: rule!EXAMPLE_DiscoverMoveSourceExpression(
    page: floor(rsp!pagingInfo.startIndex / rsp!pagingInfo.batchSize) + 1,
    genres: local!genreIds,
    keywords: if(
      isnull(rsp!searchText),
      "",
      joinarray(local!search.result.body.results.id[1],",")
    )  
  ),
  local!movies: cast(
    'type!{urn:com:appian:types:EXAMPLE}movies?list',
    local!result.result.body.results
  ),
  a!dataSubset(
    startIndex: rsp!pagingInfo.startIndex,
    batchSize: 20,
    sort: rsp!pagingInfo.sort,
    totalCount: local!result.result.body.total_results,
    data: local!movies,
    identifiers: local!movies.id
  )
)

images:ex_br_search_results.png

Configure the List View

Now that our search and filter is created, lets populate our record list with more meaningful data.

  1. In the record type, within the Record List section, ensure that the Grid option is selected for the List Style and click on Edit Record List. A new modal will appear
  2. In the Edit Record List Modal, add a new Empty grid message. Something like No movies exist with this criteria.
  3. We are going to keep all columns but Vote Count and Popularity. In the Columns section of the configuration pane, click on the red X next to the Vote Count and Popularity column.
  4. Click on the Title link. The grid configuration pane will show details about that column.
    1. Set the Weight to 2.
    2. In the navigator, click on the next column, Overview. The grid configuration pane will show you details about that column.
    3. Set the Weight to 5.
    4. Click the X next to overview in the Sort Field to remove sorting from this column.
  5. In the navigator, click on the next column, Release Date. The grid configuration pane will show you details about that column.
    1. Set the Alignment to Right.
    2. Click on the Text option with the component field.
    3. Set the Alignment to Right.
  6. In the navigator, click on the next column, Vote Average. The grid configuration pane will show you details about that column.
    1. Set the Alignment to Right.
  7. Click OK.
  8. Save your record type.

You should end up with a list view that looks like this:

images:ex_br_list_view_complete.png

Create the Summary View

A summary view for an expression-backed record is no different, structurally, from a summary view for any other type of record. What may be different, however, is how you acquire the data. For this example, our service calls will be coming from different web service operations, not the /discover/movies source that populated our list.

  1. In your test application, click on the New dropdown, and select Interface.
  2. Give the integration a name and choose a rule folder to save into.
    • Optionally add a description.
  3. Select Create. The interfac will pop-up in a new tab.
  4. Click on Expression Mode.
  5. In the Rule Inputs section, create a new rule input. Name it id and set the data type to Number(Integer)
  6. Copy the expression below and paste in the interface definition.
with(
  local!results: a!fromJson(rule!EXAMPLE_GetMovieByID(ri!id).result.body),
  local!imagePath: "https://image.tmdb.org/t/p/original/",
  {
    a!billboardLayout(
      backgroundMedia: a!webImage(
        source: local!imagePath & local!results.backdrop_path
      ),
      overlayContents: {
        a!richTextDisplayField(
          labelPosition: "COLLAPSED",
          value: a!richTextItem(
            text: index(local!results, "tagline", ""),
            size: "MEDIUM",
            style: "STRONG"
          ),
          align: "CENTER"
        )
      },
      height: "TALL"
    ),
    a!columnsLayout(
      columns: {
        a!columnLayout(
          contents: {
            a!paragraphField(
              label: "Synopsis",
              labelPosition: "ADJACENT",
              value: local!results.overview,
              readonly: true,
              height: "MEDIUM"
            ),
            a!paragraphField(
              label: "Genres",
              labelPosition: "ADJACENT",
              value: substitute(joinarray(local!results.genres.name, "|"), "|", char(10)),
              readonly: true,
              height: "MEDIUM"
            ),
            a!textField(
              label: "Release Date",
              labelPosition: "ADJACENT",
              value: local!results.release_date,
              readonly: true
            ),
            a!textField(
              label: "Budget",
              labelPosition: "ADJACENT",
              value: dollar(local!results.budget),
              readonly: true
            ),
            a!textField(
              label: "Box Office Revenue",
              labelPosition: "ADJACENT",
              value: dollar(local!results.revenue),
              readonly: true
            ),
            
          }
        ),
        a!columnLayout(
          contents: {
            a!boxLayout(
              label: "Theatrical Poster",
              contents: {
                a!imageField(
                  labelPosition: "COLLAPSED",
                  images: {
                    a!webImage(
                      source: local!imagePath & local!results.poster_path
                    )
                  },
                  size: "LARGE",
                  isThumbnail: false,
                  style: "STANDARD",
                  align: "CENTER"
                ),
                a!imageField(
                  images: a!webImage(
                    source: "https://www.themoviedb.org/assets/1/v4/logos/powered-by-rectangle-green-dcada16968ed648d5eb3b36bbcfdd8cdf804f723dcca775c8f2bf4cea025aad6.svg",
                    size: "SMALL",
                    align: "END"
                  )
                )
              },
              style: "STANDARD",
              marginBelow: "STANDARD"
            )
          }
        )
      }
    )
  }
)
  1. Save your interface.

The last steps are to get the record's title and summary view configured.

  1. Go to the Movies record type.
  2. In the Record Title section, use rf!title to give each record the title of the movie.
  3. In the View section, click on Summary to open the Edit View modal.
  4. In the Interface section, call the interface in the expression editor and pass in rp!id. You're expression should look something like the example below
    rule!EXAMPLE_SummaryView(rp!id) 
    
  5. Click OK and save the record.

Your record is complete. It should look something like:

images:ex_br_summary_view.png

Considerations When Using the Record Picker Component

If you want to use a record picker with your expression-backed record, it should just work as expected. You should not 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.

  • When a user types text into the picker field, it is equivalent to a user typing text into the search bar of the record list. The difference is that every new letter in the picker is a new call to the web service, whereas in the record list, the user must hit enter before any calls are made. This means increased load on the web service.
  • Once a record is picked, the component makes one call to the web service for every picked item to get the information displayed in the label. This could be problematic because there is often overhead in web service calls. For that reason, only use the record picker when the number of items you expect users to pick at one time is low.
  • Filters applied in the component are processed in the same way that default filters and user filters are processed. This means that any new filters in the picker needed to be handled accordingly in your source expression and data retrieval rule.

If this picker does not meet your needs in some way, use a custom picker.

FEEDBACK