Experience League | Image

L745 - The FaaSt path to Beautiful Applications

Table of Contents

  • Lesson 1 - Set up your Runtime Namespace
  • Lesson 2 - Create your first Runtime Action
  • Lesson 3 - Create your first Sequence

Lab Overview

FaaS (function as a service) is an emerging technology trend also called Serverless by the industry. Serverless computing refers to the concept of building and running applications that do not require server management. Adobe I/O Runtime is Adobe’s serverless platform that allows you to quickly deploy custom code to respond to events and execute functions right in the cloud. With your code running on top of our cloud infrastructure, I/O Runtime allows you to build custom solutions in close proximity to the content and data, bringing Adobe services together with APIs.

In this lab, you will learn:

  • What is Adobe I/O Runtime and serverless computing
  • How to create your own Runtime serverless integration with I/O Console and Adobe CLI
  • Best practice for serverless development
  • Using serverless development in event-driven Experience Cloud Use Cases

Key Takeaways

This workshop is intended to cover the following topics:

  • Adobe I/O Runtime
  • Adobe I/O CLI
  • Adobe I/O CNA Project Starter

Prerequisites

  • Workshop Info & Credentials
  • Adobe Enterprise Org
  • Adobe I/O CLI
  • Adobe I/O Runtime Access

Lesson 1. Set up your Runtime Namespace

Learning Objectives

  • Understand how to use Adobe I/O Console
  • Use Console to set up a Runtime Namespace
  • Set up your Adobe I/O CLI

Lab Tasks

  • Create new Integration on I/O Console
    • Log into Adobe I/O Console
    • Create new Integration for a Runtime Namespace
  • Set up your Adobe I/O CLI (aio-cli)
    • Configure the CLI to access your org
    • Set up Runtime Namespace

Create new Integration on I/O Console

GOAL: In this section, we are going to set up a new Integration on Adobe I/O Console that creates a new Runtime namespace.

1. Create Public Certificate

  1. Open your Terminal and run the follow commands

    $ cd Desktop
    $ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout private.key -out certificate_pub.crt
    
  2. Fill in the information as prompted for your certificate

    6

2. Create Config.json File

  1. Navigate to Adobe I/O Console at https://console.adobe.io in your browser

    • Login with the Lab Administration administrator credential that are provided on the front page. 1
  2. Select Integrations, and you should see the following screen 2

  3. Select New Integration, then Deploy serverless actions and click Continue 3

  4. Select Service Account and click Continue 4

  5. Fill in your Name and Description on this page, please use L745- + YourName (e.g. L745-SarahXu) as the name for your integration. 5

  6. From the first part, you should now see 2 new files on your Desktop, certificate_pub.crt and private.key. Upload the certificate_pub.crt file in your browser to create your Integration 7

  7. After creating your integration, you will be able to view the details of your integration. Your screen should look similar to this.

    8


Set up your Adobe I/O CLI

GOAL: In this section, we are going to set up Adobe I/O CLI that allows you to interact with your Runtime namespace.

1. Create Config.json File

  1. Find a config.json file on your Desktop. We are going to fill in the details based on the Integration you just created.

    {
      "client_id": "value from your Console Integration (String)",
      "client_secret": "value from your Console integration (String)",
      "jwt_payload": { value from your Console integration (JSON Object Literal) },
      "token_exchange_url": "https://ims-na1.adobelogin.com/ims/exchange/jwt",
      "console_get_orgs_url":"https://api.adobe.io/console/organizations",
      "console_get_namespaces_url":"https://api.adobe.io/runtime/admin/namespaces/"
    }
    
  2. Open the Integration you just created, from the Client Credentials list, copy the value of API Key (Client ID) to replace the client_id in config.json, and Client secret to replace the client_secret. 8

  3. Navigate to the JWT tab on your Integration, you should see the JWT payload block, copy it to replace the jwt_payload line in config.json. 9

  4. Save all your changes and your config.json should look something like this:

    {
      "client_id": "88f3xxxxxxxxxxxxxxxxxxxxx",
      "client_secret": "68fabxxxxxxxxxxxxxxxxxxxxx",
      "jwt_payload": {
        "exp": 1552094680,
        "iss": "2A74xxxxxxxxxxxxxxxxxxxxx@AdobeOrg",
        "sub": "12Bxxxxxxxxxxxxxxxxxxxxx@techacct.adobe.com",
        "https://ims-na1.adobelogin.com/s/ent_adobeio_sdk": true,
        "aud": "https://ims-na1.adobelogin.com/c/88f37bcfxxxxxxxxxxxxxxxxxxxxx"
      },
      "token_exchange_url": "https://ims-na1.adobelogin.com/ims/exchange/jwt",
      "console_get_orgs_url":"https://api.adobe.io/console/organizations",
      "console_get_namespaces_url":"https://api.adobe.io/runtime/admin/namespaces/"
    }
    

2. Configure Adobe I/O CLI

  1. To configure your Adobe I/O CLI, open your Terminal and run the following commands:

    $ aio config set jwt-auth Desktop/config.json --file --mime-type=application/json
    $ aio config set jwt-auth.jwt_private_key Desktop/private.key --file --mime-type=application/x-pem-file
    
  2. Your Adobe I/O CLI is now configured for your Organization. You can run the following command to validate:

    $ aio jwt-auth access-token
    

    should return an Access Token that looks like

    11

3. Select your Integration

  1. Now that your Adobe I/O CLI is configured, you can use it to select your Integration. Run the following command:

    $ aio console list-integrations
    

    this command returns a full of integrations in your Organization

    Success: Page 1 of 1, Showing 2 results of 2 results.
    <OrgID_IntegrationID> : <Integration Name 1>
    <OrgID_IntegrationID> : <Integration Name 2>
    
  2. Find your Integration from this list. You can use the following command to look to the next page if you need to:

    $ aio console list-integrations --page=2
    
  3. Once you identified your integration, use the <OrgID_IntegrationID> to select it

    $ aio console select-integration <OrgID_IntegrationID>
    

    This step tells your CLI that now you want to interact with the Runtime namespace tied with this Integration.

  4. You can validate this by typing in the following command:

    $ wsk property get
    

    which should return your Runtime credentials

    whisk auth      0ae3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    whisk API host      https://adobeioruntime.net
    whisk namespace     43611_xxxxx
    

Lesson 2. Create your first Runtime Action

Learning Objectives

  • Familiarize with Runtime concepts
  • Write simple Runtime actions

Lab Tasks

  • Runtime Hello World
    • Create a simple Hello World action
    • Invoke actions via the CLI and browser

Runtime Hello World

GOAL: In this section, let's familiarize with Runtime and the Adobe I/O CLI. Interacting with Adobe I/O Runtime currently requires the CLI (Command Line Interface). If you've completed the set up steps, you should have access to your own Runtime namespace.

Feel free to play with the CLI while I walk you through a few key concepts in Runtime.

1. Basic Hello World

Once you've configured the CLI, you can create your first function to make sure it's working.

  1. Start by creating a file called hello.js on your Desktop with the following content

    function main(params) {
      return {msg:  'Hello World!'};
    }
    
  2. Next, create the action on Runtime:

    wsk action create hello Desktop/hello.js
    

    If it's successful, you should see

    ok: created action hello
    
  3. Time to invoke the function:

    wsk action invoke hello --result
    

    You should see the following output:

    {
      "msg": "Hello World!"
    }
    
  4. You can also find out more about your activation by checking the activation log. Let's invoke it again.

    wsk action invoke hello
    

    Upon invocation, you should also see an output that looks a bit like

    ok: invoked /your-namespace/hello with id <id>
    

    Copy the ID and let's read the full activation log at

    wsk activation get <id>
    

2. Fun with Parameters

  1. Now that you've created and invoked your first action, let's try to update it to take in dynamic input. Beginning with modifying your hello.js file.

    function main(params) {
      // log the parameters to stdout
      console.log('params:', params);
    
      // if a value for name is provided, use it else use a default
      var name = params.name || 'stranger';
    
      // if a value for place is provided, use it else use a default
      var place = params.place || 'somewhere';
    
      // construct the message using the values for name and place
      return {msg:  'Hello, ' + name + ' from ' + place + '!'};
    }
    

    then update your action using

    wsk action update hello Desktop/hello.js
    
  2. Now that we have an updated action that takes params, try invoking your action again, first without parameter to see the default response

    wsk action invoke hello --result
    

    You should see the following output:

    {
      "msg": "Hello, stranger from somewhere!"
    }
    
  3. Time to pass in some parameters!

    wsk action invoke hello --result --param name "Sarah" --param place "Canton"
    

    You should see the following output:

    {
        "msg": "Hello, Sarah from Canton!"
    }
    
  4. Sometimes it is helpful to invoke an action in a blocking style and receiving the activation record entirely instead of just the result. Try it:

    wsk action invoke hello --blocking
    

    You should see the full activation log

    ok: invoked /43611_56921/hello with id 352f8bf3eb3f4619af8bf3eb3f5619fc
    {
        "activationId": "352f8bf3eb3f4619af8bf3eb3f5619fc",
        "annotations": [
            {
                "key": "limits",
                "value": {
                    "concurrency": 1,
        ...
    }
    
    

3. Understand web actions

  1. Web actions are OpenWhisk actions annotated to quickly enable you to build web based applications. Let's now turn the action we built into a web action. Open hello.js and update the code as below

    function main(params) {
      // log the parameters to stdout
      console.log('params:', params);
    
      // if a value for name is provided, use it else use a default
      var name = params.name || 'stranger';
    
      // if a value for place is provided, use it else use a default
      var place = params.place || 'somewhere';
    
      // sample object returned in a web action
      var returnObject = {
        statusCode: 200,
        headers: {
            'Content-Type': 'application/json'
        },
        body: {msg:  'Hello, ' + name + ' from ' + place + '!'}
      };
    
      // construct the message using the values for name and place
      return returnObject;
    }
    
  2. Update your hello action again, but with the --web true flag to indicate that this is a web action

    wsk action update hello Desktop/hello.js --web true
    
  3. Now, let's grab the url that we can use to call this actiON

    wsk action get hello --url
    

    This should return something that looks like https://adobeioruntime.net/api/v1/web/<NAMESPACE>/default/hello

  4. Let's paste this url into your browser and see what you receive. It should be the same json response!

    // 20190307183813
    // https://adobeioruntime.net/api/v1/web/<NAMESPACE>/default/hello
    
    {
      "msg": "Hello, stranger from somewhere!"
    }
    
  5. Challenge: Can you figure out how to modify the url so that the response says "Hello, Dragos from Iaschi!"

    • Bonus point if you know where Iaschi is :)

Lesson 3. Create your first Sequence

Learning Objectives

  • Familiarize with Runtime concepts
  • Write simple sequence

Lab Tasks

  • Introduction to Sequence
    • Create a simple sequence
    • Invoke sequence via the CLI

Introduction to Sequence

GOAL: OpenWhisk supports a special kind of action called a "sequence". These actions are created using a list of existing actions. When the sequence is invoked, each action in executed in a sequence. The input parameters are passed to the first action in the sequence. The output from that function is passed as the input to the next function and so on. The output from the last action in the sequence is returned as the response result. In this section, you will learn how to build a simple sequence in Runtime.

Using sequences is a great way to develop re-usable action components that can be joined together into "high-order" actions to create serverless applications.

For example, what if you have serverless functions to implement an external API and want to enforce HTTP authentication? Rather than manually adding this code to every action, you could define an "auth" action and use sequences to define new "authenticated" actions by joining this action with the existing API actions.

1. Create individual actions for the sequence

  1. Find the file (sequence.js). This file contains three simple functions, split, reverse and `join.

    function split(params) {
      var text = params.text || ""
      var words = text.split(' ')
      return { words: words }
    }
    
    function reverse(params) {
      var words = params.words || []
      var reversed = words.map(word => word.split("").reverse().join(""))
      return { words: reversed }
    }
    
    function join(params) {
      var words = params.words || []
      var text = words.join(' ')
      return { text: text }
    }
    
  2. Let's create the following three actions in Runtime to see what they do. In the previous chapter, we created actions based on js files. Here, we are using the same js file to define three different actions. Using the --main flag, we can define a different entry point for each action.

    wsk action create split Desktop/sequence.js --main split
    wsk action create reverse Desktop/sequence.js --main reverse
    wsk action create join Desktop/sequence.js --main join
    
  3. Time to test the actions.

    wsk action invoke split --result --param text "Hello world"
    {
        "words": [
            "Hello",
            "world"
        ]
    }
    wsk action invoke reverse --result --param words '["hello", "world"]'
    {
        "words": [
            "olleh",
            "dlrow"
        ]
    }
    wsk action invoke join --result --param words '["hello", "world"]'
    {
        "text": "hello world"
    }
    

    Can you figure out what these three actions are doing?

2. Create a sequence

  1. Now that we have three working actions, let's create an action sequence that uses all three actions to reverse the characters in each word in a phrase.

    wsk action create reverse_words --sequence split,reverse,join
    
  2. Time to test

    wsk action invoke reverse_words --result --param text "hello world"
    

    you should get a reversed string, like

    {
        "text": "olleh dlrow"
    }
    

Next Steps

Adobe I/O Runtime is currently in beta and going GA in the Summer. Come talk to the lab instructor to discuss joining the beta progran and stay tuned on adobe.io!

Additional Resources