×
Community Blog Bootstrapping Function Compute for Web Using NodeJS SDK: Part 2

Bootstrapping Function Compute for Web Using NodeJS SDK: Part 2

In this article series, we will be learning how we can bootstrap Alibaba Cloud Function Compute to the web using NodeJS SDK.

By Sai Sarath Chandra, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud's incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.

In the previous tutorial, we have created function in Alibaba Cloud Function Compute console. In this tutorial we will create a web page like below

1

We will also create a functionality where the web app can upload a file to Object Storage Service (OSS) bucket and also, we can invoke the Alibaba Cloud Function Compute console directly using NodeJS SDK.

The below is what we are trying to achieve:

2

We have created and tested the OSS Bucket and the function in function compute in last part. Now we are just trying to create web page and add functionalities

We will achieve this in three simple steps:

  1. Creating a Web Page
  2. Uploading file via OSS NodeJS SDK
  3. Invoking function via Function Compute NodeJS SDK

The whole code is available at https://github.com/saichandu415/NodeJS_FunctionComputeDemo/tree/master/client

Creating a Web Page

The whole front-end logic is written inside an index.html file. We used materialize CSS for bootstrapping.

There are certain building blocks for the UI,

<div class="row">
    <div class="input-field col s12">
        <input id="email" type="email" class="validate">
        <label for="email">Email ID</label>
    </div>
</div>

The above code snippet generates an input field along with the validation and the attribute 'type' specifies which type of input field we intended to. All the HTML5 fields are available.

<div class="row valign-wrapper">
    <div class="col s9">
        <h5>Do you want a mail to be sent with all the information?</h5>
    </div>

    <div class="col s3">
        <div class="switch">
            <label>
                Off
                <input id="mailSwitch" type="checkbox">
                <span class="lever"></span>
                On
            </label>
        </div>
    </div>
</div>

The above code snippet creates a switch like below beside a text. The key thing to notice here is to use the 'valign-wrapper' which more web developers tend to do the vertical alignment using the css properties but the materialize css provides a ready to use css class to ease the development.

3

<div id="modal1" class="modal">
    <div class="modal-content">
        <h4>File uploaded and function triggered</h4>
        <p>Find the output below</p>
        <p id="output"></p>
    </div>
    <div class="modal-footer">
        <a href="#!" class="modal-close waves-effect waves-green btn-flat">Close</a>
    </div>
</div>

The above code snippet helps us in displaying the information in a separate modal as this helps us in maintaining the single page structure, yet display the information required.

Custom.js

We also have a custom Javascript inside the html file for all the operations. The custom script is primarily calling the REST API's and propagating the response back to the UI.

One endpoint we are calling here does the task of sending the file to the OSS,

function uploadFile() {
    
        var request = {
            filepath: ''
        };
        request.filepath = document.getElementById('filepath').value;
        console.log(request);
        fetch('http://localhost:8080/api/todos', {
            method: "POST",
            headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
            body: JSON.stringify(request)
        })
        .then((res) => res.json())
        .then(function (data) {
            console.log(data);
            var instance = M.Modal.getInstance(document.getElementById('modal1'));
            document.getElementById('output').innerText = JSON.stringify(data, null, 2);
            instance.open();
            return data;
        });
    }

Here we are accomplishing a number of tasks:

  1. Calling the API in a synchronous way by using the 'fetch' API via the POST method here.
  2. Converting the response to JSON format by calling 'res.json()'
  3. After which we are displaying the information in the modal by prettifying the json with 2 spaces.
function invokeFunc(){
        var request = {
            firstname: '',
            message: 'This should capitalize',
            doMail: true,
            toMail: ''
        };
        request.firstname = document.getElementById('first_name').value;
        request.doMail = document.getElementById('mailSwitch').checked;
        request.toMail = document.getElementById('email').value;
        console.log(request);
        fetch('http://localhost:8080/api/invoke', {
            method: "POST",
            headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
            body: JSON.stringify(request)
        })
        .then((res) => res.json())
        .then(function (data) {
            console.log(data);
            M.toast({html: "Function Invoked : "+data.message, classes: 'rounded'});
            return data;
        });
    }

In the above function, the endpoint which we are calling does the work of invoking the function of the function compute directly. After getting the response, it converts to JSON and displays it as a toast message in the UI.

There are a few things happening here:

  1. We are building the request object to the endpoints using the inputs in the UI, by using DOM.
  2. Calling the endpoint in synchronous way
  3. Displaying the response in a toast.

Now, we will discuss about the endpoints which we used and what logic do they contain. Before we examine that, you need to make sure all the necessary information is being filled in the keyinfo.json under /config folder.

{
        "accessKeyId": "<YOUR ACCESS KEY ID>",
        "accessKeySecret": "<YOUR ACCESS KEY SECRET>",
        "bucket": "<YOUR BUCKET NAME>",
        "oss_region": "oss-<YOUR REGION NAME>",
        "accountId": "<YOUR ACCOUNT ID WITHOUT QUOTES>",
        "region": "<YOUR REGION NAME>",
        "fc_serviceName": "<YOUR SERVERLESS SERVICE NAME>",
        "fc_funcName": "<YOUR SERVERLESS FUNCTION NAME>"
    }

I believe all the information here are available in the console.

Let's look into how endpoints are created and what do they contain.

Navigate to client/app/routes.js which is the relevant file containing the endpoints,

Imports

var alioss = require('ali-oss');
var fc = require('@alicloud/fc');
var keyInfo = require('../config/keyInfo.json');

The key thing to functionality here is the SDK's.

ali-oss : It is the official NodeJS SDK for the OSS (Object Storage Service), using which we are going to upload the file directly to OSS>

@alicoud/fc : This is the official NodeJS SDK for the (fc) Function Compute, using which we are invoking the function.

keyInfo.json: will contain all the keys required for the Alibaba cloud SDK's.

const store = alioss({
    accessKeyId: keyInfo.accessKeyId,
    accessKeySecret: keyInfo.accessKeySecret,
    bucket: keyInfo.bucket,
    region: keyInfo.oss_region
});

The above code snippet is written in at the file level, so that the initiation happens at the start of the server which will highlight any issues that might cause due to the accesskeys. The above snippet creates an authenticated store object for OSS SDK to do further file related operations.

var client = new fc(keyInfo.accountId, {
    accessKeyID: keyInfo.accessKeyId,
    accessKeySecret: keyInfo.accessKeySecret,
    region: keyInfo.region,
    timeout: 30000 // Request timeout in milliseconds, default is 10s
});

The above is similar to the OSS store object but this is for Function Compute. This required the timeout in milliseconds to specify till when we can wait for the output of the function.

Uploading file to OSS:

app.post('/api/todos', function (req, res) {
        console.log(req.body);
        var filepath = '/Users/sarathchandrap/Desktop/testData/' + req.body.filepath;
        store.put(req.body.filepath, filepath).then((result) => {
            console.log(result);
            res.send(result);
        });
    });

The 4 lines of code above pushes a file onto the OSS with a given name and triggers a function in the Function Compute automatically. If you realize, we are using 'store.put' to upload the file to OSS.

module.exports = function (app) {
    app.post('/api/invoke', function (req, res) {

        var invokeReq = {
            firstname: req.body.firstname,
            message: req.body.message,
            doMail: req.body.doMail,
            toMail: req.body.toMail
        }
        
        var funcRes = {
            message: ''
        }
        
        client.invokeFunction(serviceName, funcName, JSON.stringify(invokeReq)).then(function(response){
            res.setHeader('Content-Type', 'application/json');
            funcRes.message = response;
            res.send(JSON.stringify(funcRes));
        });
    });

This function we are constructing the input request using parameters from the request (req.body) and also making a response object with empty information. We invoke the function using the 'client.invokeFunction' along with the serviceName, funcionName and the request.

The code provided in GitHub, particularly the client, consists of the rest API too. We can also deploy the code to the ECS instance thereby making it available over the internet. If you are planning to do so, you can find the REST API related port values under 'app/routes.js' and webapp related settings at 'server.js'.

Instructions to run the client application:

  1. Clone the code from here: https://github.com/saichandu415/NodeJS_FunctionComputeDemo
  2. Cd to client
  3. Run 'npm install' or 'npm I'
  4. Run 'npm start'

You get the following message

App listening on port 8080

Go ahead and access the app at localhost:8080

Successfully, we have created the webapp and triggered the function by uploading OSS file and also invoking the function directly using the NodeJS SDK.

0 0 0
Share on

Alibaba Clouder

2,605 posts | 747 followers

You may also like

Comments