Getting Started With Adobe I/O Runtime (Project Firefly)
By: Alex Bishop
Tags: Nodejs, React, Gdpr, Firefly, Adobe

#1 Design Overview

The requirements are very similar to the previous GDPR UI but here’s a quick re-cap of what we’re trying to achieve.

The requirements for the UI are that the user can:

i) specify whether it is an “Access” or a “Delete” request

ii) add a Ticket ID for internal records

iii) add one or more declared IDs (used as the custom key for each request)

iv) receive confirmation when the requests are registered successfully

The end result should look something like this:

#2 Environment & Project Set Up

Once you have Runtime access, the environment set up is very straightforward, just follow the steps listed here in the “Local Environment Set Up” section. The next step is to create a project; if you’re familiar with Adobe IO then you’ve probably been creating from “Empty project” but for Runtime we’ll choose the “Project from template” option:

Then select Project Firefly:

Choose a Project title and App name:

Navigate into the Stage workspace (Stage & Production workspaces are created by default but you can add more if you need to), click “Add service” and select API. There is a wide range of APIs available but we’ll go ahead and select the Privacy Service:

The next step is to create the jwt for the service account — a nice, (relatively) new feature in Adobe I/O is the option to have Adobe generate the key pair for you, which saves a little bit of time:

Once the step above is completed, the public/private keys will be downloaded to your device. The Privacy Service API should now be listed in the Stage workspace of the project, however, there won’t be any user defined actions:

To generate an action we need to switch across to the Terminal; the Runtime documentation describes what’s required, so I won’t recreate them here, just follow the steps in the help guide, starting from the section called “3. Signing in from CLI”. Once those steps are complete, the Stage workspace should show that some actions have been defined:

#3 App UI Development

The completed build includes a sample app as a starting point, which provides useful signposting for any custom code additions. We can now use the “aio app run” command in the Terminal to start up the development server and take a look at the sample app. I won’t go through every component part of the build but there are a few parts that are worth pointing out.

The first part to mention is that the sample app is built using React; you don’t necessarily need to create your UI using React — you could quite easily store your API response(s) in a window variable and use jQuery if you really wanted to — but if you want to achieve the Adobe look and feel then it’s a good idea to make use of the React Spectrum libraries.

The second piece of the puzzle is the App.js file, which has two main parts to it. The first part provides some helper functions, such as invokeAction, which allows you to send data from the UI to your backend action:

The other, equally important, part of App.js is the render() method; I’m not going to dwell on this part too much because this is definitely not a React tutorial but all you need to know is that it’s this block of code that renders the UI elements:

Most of the UI is really simple but I think it’s worth going over how each component is created:

The first part is a dropdown that allows the user to specify if it is an Access or Delete request, which translates into the code below:

The first Ticket ID / Master Consumer ID row displays when the app is loaded and looks like this:

The most complex part is dynamically adding & removing rows based on user interaction. Fortunately, I found this really nice codepen example, which is a very good fit. I don’t think it is an exact copy & paste but it’s not too far off:

Finally, the Submit button looks like this:

#4 Sending data to the backend action

The invokeAction function is included as part of the sample app build, so it is a straightforward task to make some minor updates to include the data needed for the API requests. The params object forms the request body, so needs to include the ticketID, consumerId & requestType variables that the Privacy API expects. Note that invokeAction is just triggering the backend action and passing data to it, it’s not calling the Privacy API directly:

The screenshot below shows another part of the invokeAction function; this is also included in the sample app build, so it’s just a question of being aware that the API response will be stored in actionResponse:

Part of the invokeAction function includes a call to actionWebInvoke, which is what ultimately triggers the backend action. The main thing here is to ensure that the requestDetails structure fits with what the Privacy Service API is expecting, otherwise you will see an error response:

When you execute “aio app run” in the Terminal, you have the choice to view the app on localhost or in the Experience Cloud shell. If you choose localhost you will need to ensure that you generate & pass the access token in the API request header. However, if you choose the shell option, the access token is generated automatically and passed into the request header. As shown below, the actionWebInvoke request sets new headers but also includes anything else that might already be in the headers object (i.e. the access token) via the …headers statement:

The final part of actionWebInvoke handles the response that is returned from the backend action:

#5 Privacy Service API requests

The last step in the sequence is to make the request to the Privacy Service API, which is done in the index.js file:

This part is pretty straightforward, you just need to ensure that the final structure of the request body meets the API requirements:

Anything that’s included in the actionWebInvoke request can be referenced by using the params.__ow_ prefix, which you can see examples of in the screenshots above and below:

The final part is to return the API response, which will ultimately find its way back to the actionResponse object:

#6 Handling the API response

The final task is building a table based on the response data; again, the sample app points us in the right direction by including some code that is triggered when a successful response is received. However, this just adds the “Success!” message to the UI, so I need to create a Table component that dynamically builds itself:

Essentially this just passes the existing state object — which includes the actionResponse object that contains the Privacy Service response data — through to the Table component when a successful API response is received. That state object is then accessible via the props keyword, which means the data can be re-structured into a format that makes sense for a table:

Once the data is re-structured, the map method can be used to dynamically construct the table elements:

The final step is to insert the table using the render() method:

The end result is a GDPR UI that displays Privacy Service response data in a table, which allows the employee to easily keep a record of the request details that have been submitted: