Introduction
I started to experiment with Functions and successfully got over points I think beginners could be interested in. Believe me, I'm not an expert.
Background
When I decided to write my first small own service, criteria were clear: simple and functionality that I can from time to time access with device connected to the internet.
In fact, for many general cases, there are online solutions like IFTTT where you do not need to write your own code, just combine and configure. But sometimes, there is no other chance than to write something specific.
1. Choosing Platform
I had a look at existing offers and from various cloud platforms (Amazon Web Service, Microsoft Azure, IBM Cloud, Heroku to name some of them; there are many, even you require more than just file storage) and choose Google Cloud Platform (GCP). Here are the things I considered.
1.1. Pricing
GCP allows running functionality without, for me unnecessary and expensive, full time server lease, paying just for resources (like computing time or disk space) I really require. Some cloud services are completely free, some are paid just with more extensive usage I will never reach (actually “In addition to the 2 million invocations, the free tier provides 400,000 GB-seconds, 200,000 GHz-seconds of compute time” https://cloud.google.com/functions/pricing).
During one year trial, I got $300 budget I can use freely (there are few limits like do not dig bitcoins https://cloud.google.com/terms/free-trial/), anyway in my specific case I spend nothing from it. However, after trial period GCP billing logic could change, see Bucket storage notes in 2.2.
Look at price-lists of other cloud providers to choose platform according to your needs.
Naming could be different, what Google or Microsoft call Functions is for Amazon Lambda.
If you need persistent storage, one provider often offers more solutions, from files to databases, with different pricing.
Trying to switch to another provider, you can miss some features you are used to.
1.2. Web Access
GCP allows access other webs. In clouds, such feature could be limited to paid versions (btw. “even for free tier usage, we require a valid billing account” https://cloud.google.com/functions/pricing), but during my GCP trial, I never experienced charges (actually, all under “5GB of Internet egress traffic per month“ is free https://cloud.google.com/functions/pricing).
1.3. Programming
Various platforms usually support more languages.
From Google's offer, I choose Node.JS (JavaScript) because of its simplicity. For simple scenarios (I will show few examples), GCP offers online Node.JS editor named Inline editor.
GCP beginners do not need to start with command line, cloud configuration could be done in GUI (so called console).
2. Hello World Example
When a Node.JS newbie like me opens Google's tutorial https://cloud.google.com/functions/docs/quickstart, getting to the fourth step should feel like it starts to be too complicated.
Fortunately, there is an easier way.
2.1. Environment
First time sign up for a free trial https://cloud.google.com/free/. During sign up, you will be asked for your bank card and mobile number.
Later, just get to your GCP console http://console.cloud.google.com/.
There, create a new Project. It will get internal ID similar to ProjectName-123456
and finally must be linked to Billing connected to your bank card, Billing and other console parts mentioned here are usually visible at console Home left side.
Being in your project, in Cloud Functions (not necessary in API Manager), enable the Cloud Functions API on the project.
Every step takes a few seconds.
2.2. Hello World Function
Go to Cloud Functions (if you are not already there) and Create Function.
You must choose project-unique Function name. Name can't be changed later, not liking it you must copy and delete the original Function. You will see the name in the list of project's Functions.
Choose HTTP Trigger option. It means that you can call Function by something like https://us-central1-ProjectName-123456.cloudfunctions.net/FunctionName (your exact URL is displayed under Trigger) accessing it in web browser or other software.
What it also means is that it could be called by anyone who will do the same. After first two million invocations, it has influence to your Billing. That's why in Billing (outside of Cloud Functions), you can set Budget & Alerts. In some services, it is possible to set their own extra limits.
For simple functionality, you can choose minimal possible amount of Memory allocated. Setting shorter Timeout, you will not need to wait a minute in case your function freezes.
Then, it is necessary to deal with Source code. Set Inline editor option, select index.js (both should be pre-selected) and you could see this pre-defined default script.
exports.helloWorld = function helloWorld(req, res) {
if (req.body.message === undefined) {
res.status(400).send('No message defined!');
} else {
console.log(req.body.message);
res.status(200).send('Success: ' + req.body.message);
}
};
If you do not know why 200 or 400, have a look at the List of HTTP status codes here.
As you can see, script contains one exported function helloWorld
. You must have the same helloWorld
also into Function to execute item.
Choose Stage bucket, a place where your code will be stored.
You can pre-Create Bucket in Storage. But already in Create Function, you can create New bucket also in Browse.
Next time, just Browse and Select existing.
According to Cloud Storage Always Free Usage Limits https://cloud.google.com/storage/pricing#cloud-storage-always-free Regional storage under 5 GB-months per month should be free. “Cloud Storage Always Free quotas apply to usage in us-west1, us-central1, and us-east1 regions. If you go over these usage limits and are no longer in the free trial period, you are charged according to the price sheet below.”
Function you can later move to different bucket. Edit existing function and Select new bucket. But remember that previous version (versions) of your Function stays in original bucket. In fact, every Edit creates a new bucket file, keeping old, already unused, one. You can carefully delete unused outside Cloud Functions, under Storage, Browse.
Finally, push Create button and after time Function appears in the list. Green icon means success, red failure, for example because of not matching script and Function to execute.
Being green, open your https://us-central1-ProjectName-123456.cloudfunctions.net/FunctionName (your real trigger link will be different) in new browser tab and you should get the expected output.
No message defined!
Open your Function from console's list of Functions and get into its Testing tab. Into Triggering event, paste JSON-formatted (JavaScript Object Notation) input I copied from the script comment:
{"message": "Hello!"}
or the same just divided into more lines:
{
"message": "Hello!"
}
and press Test the function button. Output should be:
Success: Hello!
Now try it with https://us-central1-Projectname-123456.cloudfunctions.net/FunctionName?message=Hello! and despite ?message=Hello!
result will be...
No message defined!
...again. It is because script evaluates req.body.message
what corresponds to http method post. When you want to react to parameter specified in URL (http method get), you will find it in req.query.message
.
3. HTML Form
Create the second Function. Steps are similar to creating the first one, just now you can start also from existing Functions's context menu (three vertical dots in list of Functions) and create is as a Copy.
Choose new project-unique Function name and enter like-this Source code.
exports.callHelloWorld = function callHelloWorld(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(
'<html><form action="helloWorld" method="post">' +
'Message: <input type="text" name="message"><br>' +
'<input type="submit" value="Send"></form></html>');
res.end();
};
Opening Function's trigger in browser displays HTML page with form which allows typing message contents and after pressing Send button, it will invoke helloWorld Function using method post.
This version requires that both Functions are in the same bucket and bucket folder, otherwise you must modify action to point to called (action could be also complete URL).
4. HTTP Request
Here is the third Function example:
exports.requestFunction = function requestFunction(req, res) {
var request = require("request");
request({
uri: "http://www.random.org/integers/?num=1&min=1&max=10&col=1&base=10&format=plain&rnd=new",
headers: {'User-Agent': 'request'},
method: "GET",
}, function(error, response, body) {
res.status(200).send('Success: ' + error + "&" + response.statusCode + "&" + body + ' end');
});
};
Script uses request
object to access random.org's URL (ok, uri) and in callback function displays returned text body. It is easy to modify example to call your cloud Function.
More about request is available here.
To use request object, it is necessary to include request module to our Function's package. In editor, switch from index.js to package.json and add there dependency.
{
"name": "sample-http",
"version": "0.0.1",
"dependencies": {
"request": "^2.81.0"
}
}
The question is how I got version of request
module.
5. Google Cloud Shell
Push Activate Google Cloud Shell button in console's top toolbar. After, while it displays Linux command shell (to believe me try cat /etc/*{release,version}
command).
Run dir
or ls
. Output should be:
node_modules README-cloudshell.txt
Now call cd node_modules
and do ls
there. You will see a list of pre-installed modules, which contains also request
. cd request
, ls
and cat package.json
- actual request
's version is there.
Try as many cd ..
as you like or simply exit
.
That's all from me about Cloud Shell.
End of Part One. In the second part, I plan to send and receive email.