Jump toUpdate content
Code examples for Serverless Functions
This page shows examples of functions in Python, Node, Golang, PHP and Rust that can be used in your Serverless Functions projects, such as functions that allow you to:
- say Hello world
- use environment variables
- use event components
- use data from CRON jobs
- connect to HTTP services
- You have an account and are logged into the Scaleway console
- You have a Serverless Functions namespace
- You have a text editor/IDE (for example Visual Studio Code or Atom)
- You understand how to package your code
Python
Returning a function result in Python
There are several ways to return a response from a handler function:
Response object with HTTP information:
def my_handler(event, context):
return {
"body": {
"message": "hello world"
},
"statusCode": 200,
"headers": {
"Content-Type": ["application/json"],
"your-header": "your-value"
}
}
Straight response without body:
def my_handler(event, context):
return {"message": "hello world"}
# or
return "my Message"
Stringified response body (AWS Lambda):
import json
def my_handler(event, context):
return {
"body": json.dumps({"message": "hello world"}),
"headers": {
"Content-Type": ["application/json"],
},
"statusCode": 200,
}
Getting data
Using environment variables
Python runtime includes the os
, which enables you to access the environment variables you define in your namespaces or functions.
The following snippet returns the environment variable ENV
you specified in the function or namespace configuration:
import os
def handle(event, context):
env_variable = os.environ.get['ENV']
print(env_variable)
return {
"body": {
"Environment variable": env_variable
},
"headers": {
"Content-Type": ["application/json"],
},
"statusCode": 200,
}
Using event objects
With event objects you can pass information through your HTTP request. They are composed of the following objects:
pathParameters
: map(string)string - Parameters defined in the path of the HTTP RequestqueryStringParameters
: map(string)string - Query Strings parameters of the HTTP Requestbody
: string|byte() - Body of the HTTP Request, you will have to parse it in your handler to use it properly.headers
: map(string)string - HTTP Request Headersmethod
: string - HTTP method usedisBase64Encoded
: boolean - Whether the request body is base64 encoded.
import json
def handle(event, context):
QueryParam = event['queryStringParameters']['parameter']
QueryBody = json.loads(event['body']) # if the body is a json
return {
"statusCode": 200,
"headers": {
"Content-Type": ["application/json"],
},
}
Using data from CRON jobs in Python
CRON jobs share the same pattern as HTTP calls. You can find the information passed into the CRON body in the event object:
import json
def handle(event, context):
CronBody = json.loads(event['body'])
return {
"statusCode": 200,
"headers": {
"Content-Type": ["application/json"],
},
}
Connecting to HTTP services in Python
You might need to get information or transmit data to an external service. The Scaleway python runtime includes the urllib
library which enables you to connect to HTTP services without adding external libraries.
Please refer to our guide on code packaging if you want to use requests.
GET
request example
from urllib import request, parse, error
import os
auth_token=os.environ['X-AUTH-TOKEN'] # you can pass token through os environment variable or secret environment variable
url={YOUR URL} # if you want a dynamic url based on informations sent to handle(), please define the url inside the function
def handle(event, context):
req = request.Request(url,method="GET")
req.add_header('X-Auth-Token',auth_token)
try:
res=request.urlopen(req).read().decode()
except error.HTTPError as e:
res=e.read().decode()
return {
"body": json.loads(res),
"headers": {
"Content-Type": ["application/json"],
},
"statusCode": 200,
}
POST
request example
from urllib import request, parse, error
import os
auth_token=os.environ['X-AUTH-TOKEN'] # you can pass token through os environment variable or secret environment variable
url={YOUR URL} # if you want a dynamic url based on information sent to handle(), please define the url inside the function
def handle(event, context):
data=json.dumps({"sample_key": "sample_value"}).encode('ascii')
req = request.Request(url, data=data, method="POST")
req.add_header('Content-Type', 'application/json')
req.add_header('X-Auth-Token', auth_token)
# Sending request to Instance API
try:
res=request.urlopen(req).read().decode()
except error.HTTPError as e:
res=e.read().decode()
return {
"body": json.loads(res),
"headers": {
"Content-Type": ["application/json"],
},
"statusCode": 200,
}
try:
res=request.urlopen(req).read().decode()
except error.HTTPError as e:
res=e.read().decode()
return {
"body": json.loads(res),
"headers": {
"Content-Type": ["application/json"],
},
"statusCode": 200,
}
If you want to use other libraries like request
, you need to upload your project using Serverless Framework (recommanded)
or by using a zip-file.
Node
Returning a function result in Node
The following examples use CommonJS modules. If you use ES modules refer to the dedicated section of this documentation.
There are multiple ways a response can return from a handler function:
- With body and statusCode. This response type sets the status code as
HTTP Response Code
, and body as the response’s body, headers asHeaders
.
Stringified body (like AWS Lambda
):
module.exports.myHandler = (event, context, callback) => {
return {
statusCode: 201,
body: JSON.stringify({
message: "async function",
}),
headers: {
"Content-Type": "application/json",
},
}
}
Not Stringified body (like AWS Lambda
):
module.exports.myHandler = (event, context, callback) => {
return {
statusCode: 201,
body: {
message: "async function",
},
headers: {
"Content-Type": "application/json",
},
}
}
- With object/entity (number, boolean, string…) without properties body and statusCode
module.exports.myHandler = (event, context, callback) => {
return {
body: "message",
headers: {
"Content-Type": ["text/plain"],
},
};
// Or
return JSON.stringify({ message: "message" });
// OR
return "Hello, world";
// OR
return 1; // true, false, undefined, null...
};
Using the callback parameter:
module.exports.myHandler = (event, context, callback) => {
const response = {
statusCode: 201,
body: {
message: "async function",
},
headers: {
"Content-Type": "application/json",
},
};
// Successful response
callback(undefined, response);
// Error response
callback(err);
};
- With a
Promise
:
module.exports.myHandler = async (event, context, callback) => {
return {
statusCode: 201,
body: {
message: "async function",
},
headers: {
"Content-Type": "application/json",
},
}
}
// OR
module.exports.myHandler = (event, context, callback) => {
const response = {
statusCode: 201,
body: {
message: "async function",
},
headers: {
"Content-Type": "application/json",
},
};
return new Promise((resolve, reject) => {
// do something
if (err) return reject(err);
return resolve(response);
});
};
Using environment variables in Node
If you need to pass information to your function you can use environment variables defined at the namespace or function level. In JavaScript they are stored in the process.env
object:
module.exports.myHandler = (event, context, callback) => {
my_parameter = process.env.MYPARAMETER
return {
statusCode: 201,
body: JSON.stringify({
parameter: my_parameter,
}),
headers: {
"Content-Type": "application/json",
},
}
}
Using event components
With the event object you can pass information through your HTTP request. It is composed of the following objects:
pathParameters
: map(string)string - Parameters defined in the path of the HTTP RequestqueryStringParameters
: map(string)string - Query Strings parameters of the HTTP Requestbody
: string|byte() - Body of the HTTP Request, you will have to parse it in your handler to use it properlyheaders
: map(string)string - HTTP Request Headersmethod
: string - HTTP method usedisBase64Encoded
: boolean - Whether the request body is base64 encoded
module.exports.myHandler = (event, context, callback) => {
queryStringParameters = event.queryStringParameters;
body = event.body;
return {
statusCode: 201,
body: JSON.stringify({
queryStringParameters: queryStringParameters,
body: body,
}),
headers: {
"Content-Type": "application/json",
},
};
};
Using data from CRON jobs in Node
CRON jobs share the same pattern as HTTP calls. You will find the information passed into the CRON body in the event object:
module.exports.myHandler = (event, context, callback) => {
body = event.body;
return {
statusCode: 201,
body: JSON.stringify({
body: body,
}),
headers: {
"Content-Type": "application/json",
},
};
};
Connecting to HTTP services in Node
You might need to get information or transmit data to an external service. The following code snippets can be executed directly in Serverless Functions without adding external libraries.
Please refer to our guide on code packaging, if you want to use fetch
, axios
, …
GET
request sample:
const https = require("https");
exports.handle = async function (event, context) {
let dataString = "";
const response = await new Promise((resolve, reject) => {
const req = https.get(
"https://pokeapi.co/api/v2/pokemon/ditto",
function (res) {
res.on("data", (chunk) => {
dataString += chunk;
});
res.on("end", () => {
resolve({
statusCode: 200,
headers: { "Content-Type": ["application/json"] },
body: JSON.stringify(JSON.parse(dataString), null, 4),
});
});
}
);
req.on("error", (e) => {
reject({
statusCode: 500,
body: "Something went wrong!",
});
});
});
return response;
};
POST
request sample
const https = require("https");
exports.handle = async function (event, context) {
let dataString = "";
const postData = JSON.stringify({
name: "John Doe",
email: "jdoe@scaleway.com",
});
const options = {
hostname: "postman-echo.com",
path: "/post",
method: "POST",
headers: {
"Content-Type": "application/json",
},
};
const response = await new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
res.on("data", (chunk) => {
dataString += chunk;
});
res.on("end", () => {
resolve({
statusCode: 200,
headers: { "Content-Type": ["application/json"] },
body: JSON.stringify(JSON.parse(dataString), null, 4),
});
});
res.on("error", (e) => {
reject({
statusCode: 500,
body: "Something went wrong!",
});
});
});
// write data to request body
req.write(postData);
req.end();
});
return response;
};
Using ES Modules
Node has two module systems: CommonJS
modules and ECMAScript
(ES
) modules. By default, Node treats your code files as CommonJS modules, however ES modules have also been available since the release of node16
runtime on Scaleway Serverless Functions. ES modules give you a more modern way to re-use your code.
According to the official documentation, to use ES modules you can specify the module type in package.json
, as in the following example:
...
"type": "module",
...
This then enables you to write your code for ES modules:
export { handle };
function handle(event, context, cb) {
return {
body: process.version,
headers: { "Content-Type": ["text/plain"] },
statusCode: 200,
};
}
The use of ES modules is encouraged, since they are more efficient and make setup and debugging much easier.
Note that using "type": "module"
or "type": "commonjs"
in your package.json will enable/disable some features in
Node runtime. For a comprehensive list of differences, please refer to the official documentation, the following is a summary only:
commonjs
is used as default valuecommonjs
allows you to userequire/module.exports
(synchronous code loading, it basically copies all file contents)module
allows you to useimport/export
ES6 instructions (asynchronous loading, more optimized as it imports only the pieces of code you need)
Go (>= 1.17)
Unlike old versions of Go runtime (< 1.17), there is no additional dependencies to use when writing a Go function.
But there are also requirements:
- your code must be a valid Go module: a
go.mod
file is expected in the root directory - your handler function should be in a file at the root of your module
- your handler must be exported, example:
Handle
is correct,handle
is not because it is not exported - your handler must have the following signature:
func Handle(w http.ResponseWriter, r *http.Request)
main
package is reserved: you must not have any package namedmain
in your module
Suggested code layout:
.
├── go.mod # your go.mod defines your module
├── go.sum # not always necessary
├── myfunc.go # your handler method (exported) must be defined here
└── subpackage # you can have subpackages
└── hello.go # with files inside
Hello world
package myfunc
import (
"encoding/json"
"net/http"
)
// Handle - Handle event
func Handle(w http.ResponseWriter, r *http.Request) {
response := map[string]interface{}{
"message": "We're all good",
"healthy": true,
"number": 4,
}
responseB, err := json.Marshal(response)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(responseB)
}
Using r *http.Request
object, you can get the method, the headers, the body, etc, as if you were using a simple http server.
You must use the w http.ResponseWriter
parameter to send a response to the function caller.
Go (< 1.17)
Our Go runtime is based on AWS lambda’s, hence you will find similarities between the two runtimes.
Hello world
Every handler must be in its package, identified by package main
, and exporting a main function with the following lambda.Start
statement:
package main
import (
"encoding/json"
"github.com/scaleway/scaleway-functions-go/events"
"github.com/scaleway/scaleway-functions-go/lambda"
)
func handler(req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
response := map[string]interface{}{
"message": "We're all good",
}
responseB, err := json.Marshal(response)
if err != nil {
return events.APIGatewayProxyResponse{}, err
}
return events.APIGatewayProxyResponse{
Body: string(responseB),
StatusCode: 200,
}, nil
}
func main() {
lambda.Start(handler)
}
In order to pass data to the function response, you need to use APIGatewayProxyResponse
, which contains the following parameters:
StatusCode
: Status Code returnedHeaders
: Response HeadersBody
: Body of the HTTP ResponseIsBase64Encoded
: boolean - Whether the response body is base64 encoded
Using environment variables in Go
If you need to pass information to your function you can use environment variables defined at the Namespace or Function level: In the following code snippet, we use environment variables to get Database configuration information
package main
import (
"database/sql"
"fmt"
"log"
"os"
"github.com/scaleway/scaleway-functions-go/events"
"github.com/scaleway/scaleway-functions-go/lambda"
)
// Initialization logic, executed at function startup
func init() {
// For example, get Database configuration from environment variables
dbName := os.Getenv("DB_NAME")
dbUser := os.Getenv("DB_USER")
dbPassword := os.Getenv("DB_PASSWORD")
dbHost := os.Getenv("DB_HOST")
dbPort := os.Getenv("DB_PORT")
connectionString := fmt.Sprintf("%s:%s@%s:%s/%s", dbUser, dbPassword, dbHost, dbPort, dbName)
db, err := sql.Open("mysql", connectionString)
if err != nil {
log.Fatalf("error received while opening connection to Database: %v", err)
}
}
// Handler executed at each invocation
func handler(req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
// Do something //...
return events.APIGatewayProxyResponse{
Body: "How to initialize stuff in a Scaleway Function",
StatusCode: 200,
}, nil
}
func main() {
lambda.Start(handler)
}
Using event components (Body, Url …)
With the APIGatewayProxyRequest
structure, you can pass information through your HTTP request:
Resource
: string - Resource path defined in API GatewayPath
: string - URL path for the callerHTTPMethod
: string - HTTP method usedHeaders
: map[string]string - HTTP Request HeadersQueryStringParameters
: map[string]string - Query Strings parameters of the HTTP RequestPathParameters
: map[string]string - Parameters defined in the path of the HTTP RequestBody
: string - Body of the HTTP Request, you will have to parse it in your handler to use it properlyIsBase64Encoded
: bool - Whether the request body is base64 encoded
package main
import (
"encoding/json"
"fmt"
"github.com/scaleway/scaleway-functions-go/events"
"github.com/scaleway/scaleway-functions-go/lambda"
)
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
fmt.Printf("HTTP method = %s.\n", request.HTTPMethod)
bodySize := len(request.Body)
fmt.Printf("Body size = %d.\n", bodySize)
fmt.Println("Headers:")
for key, value := range request.Headers {
fmt.Printf(" %s: %s\n", key, value)
}
returnedMessage := "Welcome to Scaleway"
if bodySize > 0 {
returnedMessage = request.Body
}
response := map[string]interface{}{
"message": returnedMessage,
}
responseB, err := json.Marshal(response)
if err != nil {
return events.APIGatewayProxyResponse{}, err
}
return events.APIGatewayProxyResponse{
Body: string(responseB),
StatusCode: 200,
}, nil
}
func main() {
lambda.Start(handler)
}
Using data from CRON jobs in Go
package main
import (
"encoding/json"
"github.com/scaleway/scaleway-functions-go/events"
"github.com/scaleway/scaleway-functions-go/lambda"
)
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
response := map[string]interface{}{
"message": request.Body,
}
responseB, err := json.Marshal(response)
if err != nil {
return events.APIGatewayProxyResponse{}, err
}
return events.APIGatewayProxyResponse{
Body: string(responseB),
StatusCode: 201,
}, nil
}
func main() {
lambda.Start(handler)
}
Connecting to HTTP services in Go
GET
request example
package main
import (
"github.com/scaleway/scaleway-functions-go/events"
"github.com/scaleway/scaleway-functions-go/lambda"
"io/ioutil"
"net/http"
)
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
req, err := http.Get("https://jsonplaceholder.typicode.com/posts")
if err != nil {
return events.APIGatewayProxyResponse{}, err
}
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return events.APIGatewayProxyResponse{}, err
}
return events.APIGatewayProxyResponse{
Body: string(body),
StatusCode: 200,
}, nil
}
func main() {
lambda.Start(handler)
}
POST
request example
package main
import (
"bytes"
"encoding/json"
"github.com/scaleway/scaleway-functions-go/events"
"github.com/scaleway/scaleway-functions-go/lambda"
"io/ioutil"
"net/http"
)
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
postBody, _ := json.Marshal(map[string]string{
"name": "example",
"email": "example@example.com",
})
responseBody := bytes.NewBuffer(postBody)
resp, err := http.Post("https://postman-echo.com/post", "application/json", responseBody)
if err != nil {
return events.APIGatewayProxyResponse{}, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return events.APIGatewayProxyResponse{}, err
}
return events.APIGatewayProxyResponse{
Body: string(body),
StatusCode: 200,
}, nil
}
func main() {
lambda.Start(handler)
}
Rust
Hello world
use hyper::{
Body, Request, Response, StatusCode,
};
pub async fn handle(_req: Request<Body>) -> Response<Body> {
Response::builder()
.status(StatusCode::OK)
.header("Content-type", "text/plain")
.body(Body::from("Hello from rust"))
.unwrap()
}
PHP
PHP runtime supports composer dependency management.
Adding composer.json
in your project will automatically fetch dependencies.
Returning a function result in Python
Response object with HTTP information:
<?php
function handle($event, $context) {
return [
"body" => "Hello from php",
"statusCode" => 200,
];
}
Getting data
Using environment variables
Python runtime includes the os
, which enables you to access the environment variables you define in your namespaces or functions.
The following snippet returns the environment variable ENV
you specified in the function or namespace configuration:
<?php
function handle($event, $context) {
$env = getenv('ENV');
return [
"body" => $env,
"statusCode" => 200,
];
}
Using event objects
With event objects you can pass information through your HTTP request. They are composed of the following objects:
pathParameters
: map(string)string - Parameters defined in the path of the HTTP RequestqueryStringParameters
: map(string)string - Query Strings parameters of the HTTP Requestbody
: string|byte() - Body of the HTTP Request, you will have to parse it in your handler to use it properly.headers
: map(string)string - HTTP Request Headersmethod
: string - HTTP method usedisBase64Encoded
: boolean - Whether the request body is base64 encoded.
<?php
function handle($event, $context) {
$queryparameter = $event["queryStringParameters"]["parameter"];
$querybody = $event["body"];
return [
"body" => $querybody,
"statusCode" => 200,
];
}
Using data from CRON jobs in Python
CRON jobs share the same pattern as HTTP calls. You can find the information passed into the CRON body in the event object:
<?php
function handle($event, $context) {
$cronbody = $event["body"];
return [
"body" => $cronbody,
"statusCode" => 200,
];
}