Global Navigation

  • Products
  • Overview
  • Getting Started
  • Guides
  • Resources
  • Console

Table of Contents

  • Introduction
    • App Builder Overview
    • What is App Builder
    • Business Case
    • FAQ
    • Community
  • Quick Start
    • App Builder Getting Started
      • Setting Up
      • Creating your First App
      • Publishing Your App
      • Troubleshooting
    • Runtime Getting Started
      • Overview
      • Activations
      • Deploy
      • Entities
      • How Runtime Works
      • Resources
      • Setup
      • Understanding Runtime
  • Develop
    • References
    • App Builder Guides
      • Architecture Overview
        • App Hooks
        • Introduction to React Spectrum
        • Using SDKs
      • Application State
      • Application Logging
        • Azure Log Analytics
        • New Relic
        • Splunk Cloud
        • Splunk Enterprise
      • Configuration
        • Webpack Configuration
      • Deployment
        • CI/CD for App Builder Apps
        • Credential Rotation
        • Setting Response Headers
      • Development
      • Distribution
      • Events
        • Webhooks
      • Exc App
        • Interfaces
          • Modules
          • Page ObjectWithHref
          • Page ObjectWithPath
          • Page PageAPI
          • Page PageAPIProperties
          • Runtime
          • TopBar Callback
          • TopBar CustomFeedbackConfig
          • TopBar CustomSearchConfig
          • TopBar ExternalFeedbackConfig
          • TopBar HelpCenterFeedbackConfig
          • TopBar Solution
          • TopBar TopBarAPI
          • TopBar TopBarAPIProperties
          • User UserAPI
          • User UserInfo
        • Migrate App to Exp Cloud SPA
        • Modules
          • Page
          • TopBar
          • User
      • Extensions
        • Extension Migration Guide
      • Optimization
      • Security
        • Understanding Authentication
      • Telemetry
    • Runtime Guides
      • Contribution Guide
      • Asynchronous Calls
      • Creating Actions
      • Creating REST APIs
      • CI/CD Pipeline
      • Debugging
      • Logging & Monitoring
      • Reference Docs
        • API Reference
        • CLI Usage
        • Configuring Proxy
        • Environment Variables
        • Feeds
        • Multiple Regions
        • Packages
        • Prepackages
        • Runtimes
        • Sequences & Compositions
        • Triggers & Rules
        • WSK Usage
      • Security General
      • Securing Web Actions
      • System Settings
      • Throughput Tuning
      • Tools
        • CLI Install
      • Troubleshooting
      • Using Packages
      • Using Runtime
    • Contribution Guide
  • Learning
    • Asset Compute Worker PS API
      • Requirements
      • Lesson 1: Create an app from Asset Compute template
      • Lesson 2: Configure the app
      • Lesson 3: Develop worker calling Photoshop API
      • Lesson 4: Integrate worker in AEMaaCS
      • Well done
    • Barcode Reader
      • Requirements
      • Lesson 1: Bootstrap a Headless App
      • Lesson 2: Writing a Serverless Action
      • Lesson 3: Unit and E2E Tests
      • Well done
    • Blog Articles
      • Blog Articles
    • CI/CD
      • Requirements
      • Lesson 1: Setup CI/CD
      • Lesson 2: Monitoring CI/CD
      • Lesson 3: Custom CI/CD workflow
      • Well done
    • Cron Jobs
      • Requirements
      • Lesson 1: Bootstrap a Headless App
      • Lesson 2: Set up Alarm Feed with Trigger and Rule
      • Lesson 3: Types of Alarm Feed
      • Well done
    • Custom Asset Compute Worker
      • Requirements
      • How AEM as Cloud assets works
      • Architecture of our worker
      • Configure services
      • Local environment setup
      • Implement the worker
      • Test the worker
      • Setup AEM to use the worker
      • Well Done
    • Customer Dashboard
      • Requirements
      • Lesson 1: Create a New App Builder App from Campaign Standard Template
      • Lesson 2: Explore the App Builder App
      • Lesson 3: Run the App Builder App Locally
      • Lesson 4: List All Customer Profiles on the UI
      • Lesson 5: Add Personalized Promotion Emails Triggering
      • Well Done
    • Debugging
      • Requirements
      • Lesson 1: Getting familiar with Debugger
      • Lesson 2: Debugging Application Code
      • Lesson 3: Managing Application Logs
      • Well Done
    • Event Driven
      • Requirements
      • Lesson 1: Create a New App Builder App from Template
      • Lesson 2: Register the App as Event Provider
      • Lesson 3: Fire an Event
      • Lesson 4: Consume Events
      • Well Done
    • Events Runtime
      • Requirements
      • Lesson 1: Step by Step Guide
      • Lesson 2: Verify the result
      • Well done
    • Journaling Events
      • Requirements
      • Lesson 1: Create an Event Provider using App Builder
      • Lesson 2: Create the Event Consumer using Journaling API
      • Lesson 3: End to end test
      • Well done
    • Sample Apps
      • Code Snippets
        • Caching HTTP responses
        • App Builder Files SDK
        • App Builder State SDK
        • I/O Events handler
        • Real-time data from Adobe Analytics API 1.4
    • Spectrum Introduction
      • Lesson 1: What is Spectrum ?
      • Lesson 2: Using Spectrum CSS
      • Lesson 3: Using React Spectrum
      • Lesson 4: Using React Spectrum in App Builder
      • Well done
    • Todo App
      • Requirements
      • Lesson 1: Create a New App Builder App with the React Spectrum template
      • Lesson 2: Setup Runtime actions
      • Lesson 3: Setup the CreateTodoList component
      • Lesson 4: Setup the Todo component
      • Lesson 5: Setup the TodoList component
      • Lesson 6: Bringing the pieces together to build the App
      • Well done
    • Videos
      • Overview
        • Introducing App Builder
        • Getting Started
        • Architecture
        • A Full Security Overview
        • User Journey
      • Exploring
        • Projects and Workspaces
        • React Spectrum
        • Custom Events
        • CI/CD
        • Debugging
        • Learning Resources
        • Dashboard Case Study
        • ODE Case Study
        • Deep Dive Use Cases
        • Live Wired Sneak
        • Softcrylic Partner Showcase
      • Developers Live
        • App Builder Deep Dive
        • Asset Compute Service Extensibility
        • Extend Adobe Experience Cloud
  1. Products
  2. Overview
  3. Resources
  4. Learning
  5. Todo App
  6. Lesson 2: Setup Runtime actions

Lesson 2: Set up Runtime Actions

In this lesson, we'll set up the Runtime actions to handle the CRUD operations. The will be able to handle multiple to-do lists, and each can have several to-do items.

Global configuration file


To avoid long to-do lists, we'll define a MAX_TODO_ITEMS value within a global configuration file that we will import from the actions folder and also from the web-src folder. We'll create the file at the root of the App Builder App and name it defaults.json:

{ "MAX_TODO_ITEMS": 10 }

Then, import the value in our action todolist/index.js:

const { MAX_TODO_ITEMS } = require('../../defaults.json');

In the next lesson, we'll also show how to import the value from the web-src folder.

Install aio-lib-state

We'll be using aio-lib-state to store the todo items, so first we install the dependency with:

npm i --save @adobe/aio-lib-state

Then we import it:

const stateLib = require('@adobe/aio-lib-state');

Main function

We'll setup the CRUD operations inside the main function.

Parameters

First, we define an operation parameter and make it required:

const requiredParams = ['operation'];

The operation parameter can take four possible values:

  • create to create an empty to-do list
  • read to read a to-do list
  • update to update a to-do list with a todo item
  • delete to delete a to-do list

We'll also use additional optional parameters:

  • name to identify a list
  • todo to identify a to-do inside a list
const { operation, name, todo } = params;

CRUD operations

Next, we'll initialize the state library and retrieve a todolist value with state.get().

const state = await stateLib.init(); let todoList = await state.get(`todolist`); if (todoList?.value) { todoList = todoList.value; } else { todoList = []; }

The todolist will hold all to-do listsobjects and is an empty array by default.

Finally, we'll define which operation to perform based on the value of operation and return the response:

let body = {}; switch (operation) { case 'create': // Find the todo list by name if (!todoList.find(({ name: todoListName }) => todoListName === name)) { // If none found, create an empty list with the given name todoList.unshift({ name, todos: [] }); // Store the new list in the state storage with no expiry time await state.put(`todolist`, todoList, { ttl: -1 }); body.message = `"${name}" added.`; } else { return errorResponse(400, `"${name}" already exists.`, logger); } break; case 'read': // Simply return the todo lists body.todoList = todoList; break; case 'update': if (todo) { // Find the todo list by name const foundTodoList = todoList.find(({ name: todoListName }) => todoListName === name); if (foundTodoList) { // Find the todo item by id const todoIndex = foundTodoList.todos.findIndex(({ id }) => id === todo.id); if (todoIndex !== -1) { // Update the todo item foundTodoList.todos[todoIndex] = todo; body.message = `Todo "${todo.id}" updated in "${name}".`; await state.put(`todolist`, todoList, { ttl: -1 }); } else { // Create a new todo item if (foundTodoList.todos.length < MAX_TODO_ITEMS) { foundTodoList.todos.unshift(todo); body.message = `Todo "${todo.id}" added to "${name}".`; await state.put(`todolist`, todoList, { ttl: -1 }); } else { return errorResponse(400, `Max ${MAX_TODO_ITEMS} todos reached for "${name}".`, logger); } } } else { return errorResponse(400, `${name} not found.`, logger); } } else { return errorResponse(400, `Todo is missing.`, logger); } break; case 'delete': // Filter out the todo list to delete by name const updatedTodoList = todoList.filter(({ name: todoListName }) => todoListName !== name); await state.put(`todolist`, updatedTodoList, { ttl: -1 }); body.message = `"${name}" todo list deleted.`; break; default: return errorResponse(400, 'CRUD operation not found', logger); } return { statusCode: 200, body };

For every operation except read, we are using the state.put() function to update the todolist value. We also set the time to live option to -1 so that the value of todolist won't expire.

See the full action code here.