Skip to content

Latest commit

 

History

History
306 lines (254 loc) · 16.4 KB

File metadata and controls

306 lines (254 loc) · 16.4 KB
subcollection solution-tutorials
copyright
years
2017, 2019, 2020, 2021
lastupdated 2021-01-21
lasttested 2020-12-22
content-type tutorial
services openwhisk, api-gateway, Cloudant, cloud-object-storage
account-plan paid
completion-time 2h

{:step: data-tutorial-type='step'} {:shortdesc: .shortdesc} {:new_window: target="_blank"} {:codeblock: .codeblock} {:screen: .screen} {:tip: .tip} {:pre: .pre}

Serverless web application and API

{: #serverless-api-webapp} {: toc-content-type="tutorial"} {: toc-services="openwhisk, api-gateway, Cloudant, cloud-object-storage"} {: toc-completion-time="2h"}

This tutorial may incur costs. Use the Cost Estimator to generate a cost estimate based on your projected usage. {: tip}

In this tutorial, you will create a serverless web application using a bucket in {{site.data.keyword.cos_short}} and implementing the application backend using {{site.data.keyword.openwhisk}}. {: shortdesc}

As an event-driven platform, {{site.data.keyword.openwhisk_short}} supports a variety of use cases. Building web applications and APIs is one of them. With web apps, events are the interactions between the web browsers (or REST clients) and your web app, the HTTP requests. Instead of provisioning a virtual machine, a container or a Cloud Foundry runtime to deploy your backend, you can implement your backend API with a serverless platform. This can be a good solution to avoid paying for idle time and to let the platform scale as needed.

Any action (or function) in {{site.data.keyword.openwhisk_short}} can be turned into a HTTP endpoint ready to be consumed by web clients. When enabled for web, these actions are called web actions. Once you have web actions, you can assemble them into a full-featured API with API Gateway. API Gateway is a component of {{site.data.keyword.openwhisk_short}} to expose APIs. It comes with security, OAuth support, rate limiting, custom domain support.

Objectives

{: #serverless-api-webapp-0}

  • Deploy a serverless backend and a database
  • Expose a REST API
  • Host a static website
  • Optional: Use a custom domain for the REST API

The application shown in this tutorial is a simple guestbook website where users can post messages.

Architecture

  1. The user accesses the application hosted on the bucket in {{site.data.keyword.cos_short}}
  2. The web application calls a backend API.
  3. The backend API is defined in API Gateway.
  4. API Gateway forwards the request to {{site.data.keyword.openwhisk_short}}.
  5. The {{site.data.keyword.openwhisk_short}} actions use {{site.data.keyword.cloudant_short_notm}} to store and retrieve guestbook entries.

Create the Guestbook database

{: #serverless-api-webapp-2} {: step}

Let's start by creating an {{site.data.keyword.cloudant_short_notm}} service instance. {{site.data.keyword.cloudant_short_notm}} is a fully managed JSON document database. {{site.data.keyword.cloudant_short_notm}} is built upon and compatible with Apache CouchDB.

  1. In the Catalog, under Services, go to the Databases category. Click on the {{site.data.keyword.cloudant}} tile. In the new dialog:
    1. Under Multitenant select a region.
    2. Under Configure Cloudant instance pick a unique name for the service, such as <yourinitials>-guestbook-db.
    3. Select a resource group.
    4. Select IAM and legacy credentials as authentication method.
    5. Select the Lite plan. If you already have a Lite plan in your account, select another service plan.
    6. Click Create.
  2. Back in the {{site.data.keyword.Bluemix_short}} Resource List, under Services, click on the {{site.data.keyword.cloudant}} instance you created to open the instance full details page. Note: You may be required to wait until the status of the service changes to Active.
  3. Click on Launch Dashboard to open the dashboard in a new browser tab.
  4. In the upper right, click on Create Database. Enter guestbook as name and select Non-Partitioned under Partitioning. Click Create to create the database.
  5. Switch back to the browser tab with the service dashboard page. Go to Service credentials, then:
    1. Click New credential.
    2. Set the name to for-guestbook. Leave the role as Manager.
    3. Click Add to add the new credentials.
    4. Expand the newly created credentials and review them. We will need these credentials later to allow Cloud Functions actions to read/write to your Cloudant service.

Create serverless actions

{: #serverless-api-webapp-3} {: step}

In this section, you will create serverless actions (commonly termed as Functions). {{site.data.keyword.openwhisk}} (based on Apache OpenWhisk) is a Function-as-a-Service (FaaS) platform which executes functions in response to incoming events. Serverless functions only incur charges for the execution time.

Sequence of actions to save the guestbook entry

{: #serverless-api-webapp-4}

You will create a sequence which is a chain of actions. In a sequence, the output of one action acts as input to the following action and so on. The first sequence you will create is used to persist a guest message. Provided a name, an emailID and a comment, the sequence will:

  • Create a document to be persisted.
  • Store the document in the {{site.data.keyword.cloudant_short_notm}} database.

Start by creating the first action:

  1. In the browser, open a tab and go to Functions.
  2. From the namespace drop-down, either select an existing namespace or use Create Namespace to create a new one.
  3. Go to the Actions list.
  4. Create a new action:
    1. Set Name as prepare-entry-for-save as name.
    2. Click Create Package to create a new package with name guestbook.
    3. Pick a Node.js as Runtime (Note: Pick the latest version).
    4. Click Create to create the action.
  5. In the new dialog replace the existing code with the code snippet below:
    /**
     * Prepare the guestbook entry to be persisted
     */
    function main(params) {
      if (!params.name || !params.comment) {
        return Promise.reject({ error: 'no name or comment'});
      }
    
      return {
        doc: {
          createdAt: new Date(),
           name: params.name,
           email: params.email,
           comment: params.comment
        }
      };
    }
    {: codeblock}
  6. Thereafter click Save.

Then add the action to a sequence:

  1. On the left pane, click on Enclosing Sequences and then Add To Sequence.
  2. Under Create New set the Sequence Name to save-guestbook-entry-sequence and choose guestbook as package.
  3. Select guestbook for the Enclosing Package
  4. Then finish by clicking Create and Add.

Now, add the second action to that sequence:

  1. Click on the entry save-guestbook-entry-sequence. It opens sequence details. Then click Add on the upper right.
  2. Instead of Create New select Use Public. It loads and displays icons for available integrations. Pick Cloudant.
  3. Under Actions choose create-document.
  4. Create a New Binding and complete the form as follows:
    1. Set Name to binding-for-guestbook.
    2. For Instance select your instance, for the credentials for-guestbook as created earlier, and as Database pick guestbook.
  5. Click Add, thereafter Save.
  6. To test the entire sequence, click on Invoke with parameters and enter the JSON below
       {
         "name": "John Smith",
         "email": "john@smith.com",
         "comment": "this is my comment"
       }
    {: codeblock}
  7. Click Invoke.

Sequence of actions to retrieve entries

{: #serverless-api-webapp-5}

The second sequence is used to retrieve the existing guestbook entries. This sequence will:

  • List all documents from the database.
  • Format the documents and return them.
  1. Under Functions, click on Actions and then Create.
  2. Then, after selecting Action, use set-read-input as name. Again, select guestbook as package and a Node.js version as runtime. Click Create.
  3. In the action details, replace the existing code with the code snippet below. This action passes the appropriate parameters to the next action in the sequence.
    function main(params) {
      return {
        params: {
          include_docs: true
        }
      };
    }
    {: codeblock}
  4. Click Save.

Add the action to a sequence:

  1. Similar to earlier, click on Enclosing Sequences, Add to Sequence and Create New.
  2. Enter read-guestbook-entries-sequence for the Sequence Name
  3. Select guestbook for the Enclosing Package and click Create and Add.

Complete the sequence:

  1. Click on read-guestbook-entries-sequence sequence and then click Add to create and add the second action to get documents from {{site.data.keyword.cloudant_short_notm}}.
  2. Under Use Public, choose {{site.data.keyword.cloudant_short_notm}} and then list-documents
  3. Under My Bindings, choose binding-for-guestbook and Add to create and add this public action to your sequence.
  4. Click Add again to create and add the third action which will format the documents from {{site.data.keyword.cloudant_short_notm}}.
  5. Under Create New enter format-entries for name
  6. Click guestbook for the Enclosing Package and then click Create and Add.
  7. Click on format-entries and replace the code with below:
    const md5 = require('spark-md5');
    
    function main(params) {
      return {
        entries: params.rows.map((row) => { return {
          name: row.doc.name,
          email: row.doc.email,
          comment: row.doc.comment,
          createdAt: row.doc.createdAt,
          icon: (row.doc.email ? `https://secure.gravatar.com/avatar/${md5.hash(row.doc.email.trim().toLowerCase())}?s=64` : null)
        }})
      };
    }
    {: codeblock}
  8. Click on Save.
  9. Choose the sequence by clicking on Actions and then read-guestbook-entries-sequence.
  10. Click on Save and then Invoke.

Create an API

{: #serverless-api-webapp-6} {: step}

  1. Go to Actions.
  2. Select the read-guestbook-entries-sequence sequence. Next to the name, click on Web Action, check Enable as Web Action and Save.
  3. Do the same for the save-guestbook-entry-sequence sequence.
  4. Go to APIs and click Create API (or Create Managed API if you have existing APIs).
  5. Set the API name to guestbook and, accordingly, the base path to /guestbook.
  6. Click on Create operation and create an operation to retrieve guestbook entries:
    1. Set path to /entries
    2. Set verb to GET
    3. Select the read-guestbook-entries-sequence action
  7. Click on Create operation and create an operation to persist a guestbook entry:
    1. Set path to /entries
    2. Set verb to PUT
    3. Select the save-guestbook-entry-sequence action
  8. Scroll to the end of the page to Create the API. Make note of the provided route, as you will use it from your web application.

Deploy the web app

{: #serverless-api-webapp-7} {: step}

Create a {{site.data.keyword.cos_short}} bucket configured with static website hosting containing the files for the guestbook javascript application that uses the cloudant database.

Create a {{site.data.keyword.cos_short}} instance:

  1. Select Cloud Object Storage from the catalog
  2. Chose a unique service name for the insrtance, such as <yourinitials>-guestbook-cos
  3. Select a resource group.
  4. Click Create

Create a bucket configured for static website hosting:

  1. Click Create a bucket
  2. Click Custom bucket
  3. Enter a bucket name that is unique is across all IBM accounts. Try <yourinitials>-guestbook.
  4. Select Resiliency Regional
  5. Select a Location, choose a region consistent with the {{site.data.keyword.cloudant_short_notm}} instance
  6. Keep the Storage class default
  7. Scroll down to the Static website hosting and click Add rule
  8. Keep the Routing rules (individual) selected and add the Index document index.html
  9. Click Public access to On
  10. Click Save
  11. Scroll to the bottom and click Create bucket

Copy the files in the docs directory of https://github.com/IBM-Cloud/serverless-guestbook into the bucket:

  1. Open https://github.com/IBM-Cloud/serverless-guestbook in a new tab.
  2. Download a zip file by clicking Code then Download ZIP.
  3. Unzip the file and navigate to the docs directory of the unzipped file.
  4. Edit guestbook.js - replace the value of apiUrl with the route you made a note of earlier when creating the API.
  5. Open the bucket Objects view and drag and drop the guestbook.js and index.html files to the COS bucket.
  6. Navigate to the Configuration tab for the bucket and scroll down to the Static website hosting endpoints section to copy the Public endpoint into a browser tab.
  7. You should see the test guestbook entry created earlier.
  8. Add new entries.

Guestbook Screenshot

Optionally configure a custom domain

{: #serverless-api-webapp-custom-domain} {: step} You can optionally create a custom domain for the API. Earlier you made note of the custom route and copied it into guestbook.js. A CNAME record can be added to your custom domain in a DNS provider. Instructions to create a custom domain for an API using {{site.data.keyword.cis_full_notm}} and {{site.data.keyword.openwhisk_short}} can be found in Deploy serverless apps across multiple regions.

A custom domain can also be assigned to the static website bucket. Follow the instructions at Domain Routing for IBM Cloud Object Storage static web hosting. Navigate to the Configuration tab for the bucket and scroll down to the Static website hosting endpoints section to copy the Public endpoint that will be used for the CNAME target.

Remove resources

{: #serverless-api-webapp-cleanup} {: step}

To delete the created bucket and {{site.data.keyword.openwhisk_short}} service:

  1. Navigate to the {{site.data.keyword.cos_short}} bucket objects
  2. Check the box in the title row to select all objects in the bucket
  3. Click Delete objects
  4. In the upper right of the bucket object page Actions menu select Delete bucket
  5. In the upper right of the {{site.data.keyword.openwhisk_short}} instance Actions menu select Delete Service

To delete the created {{site.data.keyword.cloudant_short_notm}} service,

  1. Navigate to resource list
  2. Under Services, click on the action menu next to <yourinitials>-guestbook-db service
  3. Click Delete

To delete the API and actions from {{site.data.keyword.openwhisk_short}},

  1. Navigate to {{site.data.keyword.openwhisk_short}} landing page.
  2. On the left pane, click on APIs.
  3. Click on the delete icon in the guestbook API row and then Delete on the modal window.
  4. On the left pane, click on Actions.
  5. Under the guestbook package, delete all the actions by clicking on the delete icon in the respective action rows.

Related content

{: #serverless-api-webapp-13}