In a Nutshell
Serverless computing is the atomization of cloud computing into units of functions, which are usually endpoints. Then, instead of getting billed for the servers that host your application 24/7 (or when your servers are on), you get billed for the execution time of those functions.
Migrating to a Stateless Architecture
You can ‘cheat’ on the statelessness by linking to databases that hosts your state(s) - this can make sense if your state isn’t something that changes too frequently.
- Atomize an app into (mostly stateless) functions.
- Host on a platform of your choice, such as AWS Lambda or GCP Functions.
- Profit!
Advantages
- Pay only for the execution time of your application.
Disadvantages
- Security concerns of hosting servers outside of your premisis.
- It might make more economic sense to use entire servers 24/7 depending on your application.
- Not all languages are supported on all platforms, although new technologies such as wasmer are promising to offset this particular disadvantage.
Practical Example
Let us build a very simple application: a password generator.
Requirements
- Easy to remember.
- Easy to type.
- Difficult to guess.
- Difficult to brute-force.
- Meets requirements of modern passwords; a mixture of
- uppercase letters,
- lowercase letters,
- special characters, and
- numbers.
Solution
Use xkcd-ish passwords.
To generate xkcd-ish passwords, we need a dictionary of simple words. Luckily, the Wordle game craze meant many such suitable dictionaries popped up in the open-source world. Let’s use MikhaD’s Wordle dictionary.
# words.py
WORDS = ["cigar", "rebut", "sissy", ...] # copied from MikhaD's dictionary
Now we will use this dictionary to generate a password in the <Word1><Delimiter><Number><Delimiter><Word2>
format:
# passgen.py
import secrets
import string
import words
def passgen(word_count, delimiter, contains_number, title_case):
# do sanity checks here
base_pass = [secrets.choice(words.WORDS) for _ in range(word_count)]
if title_case:
base_pass = [x.title() for x in base_pass]
if contains_number:
pos = round(word_count / 2.0)
base_pass[pos:pos] = [str(secrets.randbelow(100))]
return delimiter.join(base_pass)
For other miscillaneous functionalities, we group them into a single module.
# utils.py
def str_to_bool(string):
if string.lower() in ["true", "t", "1"]:
return True
if string.lower() in ["false", "f", "0"]:
return False
raise ValueError(f"Could not parse '{string}' to bool type.")
Deployment
You need to have an AWS account for this! Caution: this makes your function callable by anyone; you will be billed for each call! If you have followed all the instructions correctly, you should be presented with a screen showing your function’s URL and an IDE to add or edit your code. Using said IDE, copy and paste the codes we created earlier into the IDE, and edit the special file called Your folder structure should now look like this: The module called Here, Refer to the documentation for more information on We return a dictionary of two keys: Once done, click on Deploy. After a few seconds, your function should be deployed and visiting function URL using your browser should print a password.AWS Lambda
lambda_function.py
as follows.# lambda_function.py
from passgen import passgen
from utils import str_to_bool
def lambda_handler(event, context):
return {
"statusCode": 200,
"body": {
"password": passgen(
word_count=int(event.get("word_count", 2)),
delimiter=str(event.get("delimiter", "-")),
contains_number=str_to_bool(event.get("contains_number", "True")),
title_case=str_to_bool(event.get("title_case", "True")),
)
},
}
.
└── generatePassword
├── lambda_function.py
├── passgen.py
├── utils.py
└── words.py
lambda_function
is the default entrypoint module and a the function with the signature lambda_handler(event, context)
is the default entrypoint.event
is a dictionary containing the request parameters; in our case these are:
word_count
, an integer to indicate how many words will be used.delimiter
, the string delimiter between words.contains_number
, a boolean indicating whether or not a number will be used.title_case
, a boolean indicating whether or not the words will be in title case.context
.
statusCode
, set to 200 because we have successfully executed our function, andbody
, the response payload. In addition to the password, information such as the password difficulty in terms of entropy could be given.
You need to have a GCP account for this! Caution: this makes your function callable by anyone; you will be billed for each call! Using the IDE given, copy and paste the codes we created earlier into the IDE, and edit the special file called Your folder structure should now look like this: The module called Here, We return the response payload as a dictionary. In addition to the password, information such as the password difficulty in terms of entropy could be given. Once done, click on DEPLOY. After a few seconds, your function should be deployed and visiting function URL using your browser should print a password.GCP Functions
generate_password
.
main.py
as follows.# main.py
import functions_framework
from passgen import passgen
from utils import str_to_bool
@functions_framework.http
def generate_password(request):
return {
"password": passgen(
word_count=request.args.get("word_count", default=2, type=int),
delimiter=request.args.get("delimiter", default="-", type=str),
contains_number=request.args.get("contains_number", default=True, type=str_to_bool),
title_case=request.args.get("title_case", default=True, type=str_to_bool),
)
}
.
├── main.py
├── passgen.py
├── requirements.txt
├── utils.py
└── words.py
main
is the default entrypoint module and we set the function with the signature generate_password(request)
as the default entrypoint.request
is a Flask Request structure containing the request parameters; in our case these are:
word_count
, an integer to indicate how many words will be used.delimiter
, the string delimiter between words.contains_number
, a boolean indicating whether or not a number will be used.title_case
, a boolean indicating whether or not the words will be in title case.
Congratulations: you’ve just created your first serverless application!