A few months ago, we published an article presenting the new serverless trend. Today, we invite you to get your hands dirty and to use this technology to create a graphic representation application for the latency of a third-party website. Without deploying a sing physical or virtual server (at least not knowingly), and with very little code, the following result can thus be archieved:

AWS Lambda site serverless

Serverless application: choice of weapons

Like we explained in our previous article, the cornerstone of a serverless architecture is the AWS Lambda / API Gateway duo. Of course, these two services can be independently manipulated by hand, but not only! Lately, a load of new projects were developed allowing the management, within a single software, of the sending of Lambda functions and their association with an entry point through the API Gateway.

Among the most popular, there are Serverless, Zappa and Chalice. Chalice, straight from Amazon, will be our choice for the rest of this article. We immediately liked its logic and handiness, which tipped the balance in its favor! (thanks Jean 😉 )

The first stone of serverless architecture

The use and installation of Chalice are very simple and follow the python standards. We have to make sure not to pollute our file system with useless dependencies, and to create a python virtualenv for the occasion:

$ virtualenv ve/chalice

$ . ve/chalice/bin/activate

(chalice) $ pip install chalice

In order to connect to AWS, Chalice reads the file ier ~/.aws/config, just like awscli. If it does not exist, it has to be created with the following information:

$ cat >> ~/.aws/config

[default]

aws_access_key_id=VOTRE_ACCESS_KEY

aws_secret_access_key=VOTRE_SECRET_KEY

region=VOTRE_REGION (eu-central-1, eu-west-1, etc)

Your access key and your secret key are available in your IAM AWS console. Once the file is created, our first project can be launched:

(chalice) $ chalice new-project sltest

A directory full with many files then appears:

(chalice) $ ls -l

-rw-r--r--   app.py

-rw-r--r--   requirements.txt

Here, requirements.txt contains the list of your application’s potential dependencies. App.py is basic python code, whose structure resembles the fabulous microframework Flask. The basic principle is the same: we register routes which will be then registered into AWS’s API gateway. In the app.py file, python code is associated with these routes, like for instance the following one which would display “Hello world”:

from chalice import Chalice

 

app = Chalice(app_name='helloworld')

 

@app.route('/')

def index():

return {'hello': 'world'}

We are going to change this example code, to make it do something more useful. With the help of the python-requests library, we will make it provide the access time and return code of a website used as a parameter:

from chalice import Chalice

import requests

 

app = Chalice(app_name='sltest')

app.debug = True

 

@app.route('/status/{website}')

def status(website):

try:

r = requests.get('http://{0}/'.format(website))

return {'rc': r.status_code, 'time': r.elapsed.total_seconds()}

except requests.ConnectionError:

return {'rc': -1, 'time': -1}

Here, we register a route in the /status/<fqdn> format, and we receive, as requested, a dictionary containing the return code of the page and its response time.

The use of the third-party module python-requests (non mandatory) implies the addition, in the requiremens.txt file, of the following line:

requests

The code is now deployed with Chalice, which provides us, at the end of its work, the URL through which we can access the redult of our work (here, https://monbackend/) :

(chalice) $ chalice deploy

...

Initiating first time deployment...

https://monbackend/

And we can already use this service, for instance with curl or httpie:

$ http https://monbackend/status/nbs-system.com

HTTP/1.1 200 OK

Access-Control-Allow-Origin: *

Connection: keep-alive

Content-Length: 29

Content-Type: application/json

Date: Mon, 12 Dec 2016 12:04:33 GMT

Via: 1.1 dbde8ac00ce406599a623c34e6eb8a7b.cloudfront.net (CloudFront)

X-Amz-Cf-Id: ZSSmtUHWfTDw08jZ52BQ3zddJ_yk-g0u9sX1y_H68Vg9DVBUh8xNEg==

X-Amzn-Trace-Id: Root=1-584e924f-8352808d2988ddd4ca8be7b1

X-Cache: Miss from cloudfront

x-amzn-RequestId: 23c4964f-c063-11e6-a6ec-e79dcf59fbd8

 

{

"rc": 200,

"time": 0.204534

}

It works, it is infinitely scalable and we have not deployed a single machine ourselves.

A website presentation… still serverless!

Of course, a backend will only satisfy the needs of a developer. To present the data in an elegant way, it will have to be displayed, for instance with a website. In this perspective, AWS S3 enables us to set up a simple static page, publicly accessible, and whose javascript/jQuery code will request the API Gateway to present the data “live”.

Highcharts is a known, easy-to-use javascript framework, used a lot to graphically represent data. A perfectly functionnal demonstration code will be the base of our mini latency monitor. For presentation’s sake, we also included bootstrap, but you can decorate your site the way you want.

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Bootstrap 101 Template</title>

 

<!-- Bootstrap -->

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
 integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" 
 crossorigin="anonymous">

 

</head>

<body>

 

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
 integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" 
 crossorigin="anonymous"></script>

<script src="https://code.highcharts.com/highcharts.js"></script>

 

<script>

 

var chart;

var fqdn = 'www.example.com';

 

function statuslabel(s) {

$('span.label').removeClass().addClass('label label-' + s);

}

 

function requestData() {

 

$.ajax({

// Ici on accède au backend déployé précédemment

url: 'https://monbackend/status/' + fqdn,

method: 'GET',

success: function(rc) {

var series = chart.series[0],

shift = series.data.length > 20;

point = [(new Date()).getTime(), rc.time];

 

// add the point

chart.series[0].addPoint(point, true, shift);

 

// call it again after one second

setTimeout(requestData, 1000);

fqdn = $('#fqdn').val();

if (rc.rc < 0) {

statuslabel('danger');

} else {

statuslabel('success');

}

 

},

error: function() {

fqdn = $('#fqdn').val();

setTimeout(requestData, 1000);

statuslabel('danger');

},

cache: false

});

}

 

$(document).ready(function() {

chart = new Highcharts.Chart({

chart: {

renderTo: 'container',

defaultSeriesType: 'spline',

events: {

load: requestData

}

},

title: {

text: 'Live latency'

},

xAxis: {

type: 'datetime',

tickPixelInterval: 150,

maxZoom: 20 * 1000

},

yAxis: {

minPadding: 0.2,

maxPadding: 0.2,

title: {

text: 'Value',

margin: 80

}

},

series: [{

name: 'Random data',

data: []

}]

});

});

</script>

 

<div id="container" style="width:100%; height:400px;"></div>

 

<div class="form-group" style="width:30%; margin-left:20px;">

<label for="usr">FQDN

<span class="label label-default">status</span>

</label>

<input type="text" class="form-control" id="fqdn">

</div>

 

</body>

</html>

In this Javascript / HTML code piece, the AJAX function is particularly interesting. It calls the backend that was previously published with Chalice. For the looks still, we added a small label that will change color depending on the availability of the website written in the input text zone.

We publish this mini website on AWS S3 with the help of awscli:

$ aws s3 cp sltest.html s3://monbucket/ --acl public-read

At this point, an action is needed to allow your browser to treat the AJAX request we talked about earlier. Indeed, on recent browsers, our little demonstration will not work, since they won’t send a request to another domain without its authorization. To authorize the call of the backend from the fronted from your browser, the CORS option (cross-origin resource sharing) for the called URL of the backend, in the API Gateway section of AWS console:

AWS Lambda activation de Cors

Once the activation of CORS is approved, we must not forget to re-deploy the API (in the same menu). Yes, I forgot a few times and spent several precious minutes trying to understand why nothing was displayed…

Serverless technology: it is only the beginning…

You must admit that we made our first serverless and infinitely scalable website with disconcerting ease! Ok, ok, I already hear haters saying we did not need the Lambda section in python, that we could have made this latency graph in real time using only Javascript; and it’s true. But the idea, here, it to expose the methodology and to open possibilities! From this simple example, we can now extrapolate all parts of the code, interact with a database, create new entry points for our backend, make a very complicated website… without having to care about the maintenance of the underlying instances.

Emile Heitor
Emile Heitor
After being NBS System’s CTO, Emile now guides our clients in their most complex projects, especially on the AWS public Cloud. A renown expert in IT, always at the forefront of technology, he understand and makes understand the stakes and evolutions of the field.