Go Template

This enables allows you to code functions using Golang 1.19. The handle function defines the HTTP request handler logic. This function must implement the logic that the function should execute each time it is invoked.
package function

import (
	"io/ioutil"
	"net/http"
)

// Handle defines the logic of the HTTP request handler.
//
// This example echoes the HTTP request payload by returning a response with
// status code 200 and the same payload used in the request.
func Handle(w http.ResponseWriter, r *http.Request) {
	var body []byte

	if r.Body != nil {
		defer r.Body.Close()
		body, _ = ioutil.ReadAll(r.Body)
	}

	w.WriteHeader(http.StatusOK)
	w.Write(body)
}
The Handle function is the HTTP Handler in which your code will run. You can use other functions in your code to make it cleaner, but the Handle function is the entry point of your serverless function. Check these sources for further information about Go handlers:

Libraries

Adding third-party dependencies is not allowed at the moment. For now, you can use the following pre-installed dependencies (this list will grow):

SWX Package

The function/swx package allows you to obtain and revoke access tokens for the Altair IoT Studio REST API.
Note: This package is in a very early stage of development. More features will be added in the future.

Variables

You can access any variable information stored under the Variables Storage using the two built-in functions in the function/variables package:

  • func Get(variableName string) string: Returns the value of the given variable. If the variable is not found, an empty string is returned.
  • func Exists(variableName string) bool: Returns a boolean value indicating if the given variable is found.
Example:
package function

import (
	"function/variables"
	"net/http"
)

func Handle(w http.ResponseWriter, r *http.Request) {
	// ...
	if variables.Exists("my_password") {
		mySecret := variables.Get("my_password")
		// ...
	}
	// ...
}

Logging

Anything you write to stderr is saved as a log entry. You can use the log package for that:
package function

import (
        "log"
        "net/http"
)

func Handle(w http.ResponseWriter, r *http.Request) {
        // ...

        log.Println("My log entry!")
        
        // ...

}

Examples

Here are some simple examples to illustrate how you can write your own functions using Go.

Adder
This is a really simple function that gets a comma-separated list of numbers in the request body and return the sum of them (or an error if the input format is invalid).
package function

import (
        "fmt"
        "io/ioutil"
        "net/http"
        "strconv"
        "strings"
)

func Handle(w http.ResponseWriter, r *http.Request) {
        var body []byte
        var sum float64 = 0

        //Gets function input
        if r.Body != nil {
            defer r.Body.Close()
            body, _=ioutil.ReadAll(r.Body)
        }

        // Parses input as a comma-separated list of numbers
        numbers := strings.Split(string(body), ",")

        //Tries to convert all values to numbers
        for _, number :=range numbers {
            number = strings.TrimSpace(number)
            if value, err :=strconv.ParserFloat(number, 32); err != nil {
                    //Throws an error if something is not a number
                    w.WriteHeader(http.StatusBadRequest)
                    w.Write([]byte("Invalid input format!"))
                    return
            } else {
                    sum += value
            }
        }

        w.WriterHeader(http.StatusOK)
        w.Write([]byte(fmt.Sprintf("%f", sum)))
}
MQTT Publisher
The following example shows how to set up an MQTT client to publish the payload of the request to the functions/go topic.
package function

import (
	"fmt"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"io/ioutil"
	"net/http"
)

const (
	MQTTBroker = "test.mosquitto.org"
	MQTTPort   = 1883
)

func Handle(w http.ResponseWriter, r *http.Request) {
	var input []byte

	if r.Body != nil {
		defer r.Body.Close()
		input, _ = ioutil.ReadAll(r.Body)
	}

	opts := mqtt.NewClientOptions()
	opts.AddBroker(fmt.Sprintf("tcp://%s:%d", MQTTBroker, MQTTPort))
	client := mqtt.NewClient(opts)
	if token := client.Connect(); token.Wait() && token.Error() != nil {
		panic(token.Error())
	}
	t := client.Publish("functions/go", 0, false, input)
	<-t.Done() // Wait until message is published
	if t.Error() != nil {
		panic(t.Error())
	}

	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Message published!"))
}
Update a Thing's Property
The following example shows how to update a Thing's Property using the swx package to deal with token request and revocation.
package function 
 
import ( 
   "fmt" 
   "function/swx" 
   "function/swx/auth" 
   "io/ioutil" 
   "net/http" 
 
   "github.com/go-resty/resty/v2" 
) 
 
// We'll use a Thing credentials to request the access token 
var ( 
   ApiUrl       = "https://api.swx.altairone.com" 
   Space        = "examples" // Change it to your Space name 
   Category     = "<A-CATEGORY-NAME>" 
   ThingID      = "<A-THING-ID>" 
   ClientID     = "<A-CLIENT-ID>" 
   
) 
 


func Handle(w http.ResponseWriter, r *http.Request) {
  // Get the client secret from the Secrets Storage.
  // This avoids hardcoding the secret in the code.
  clientSecret := secrets.Get("my_secret_name")


  token, err := auth.GetToken(ClientID, clientSecret, []string{"thing.update"})
  if err != nil {
    w.WriteHeader(err.(*swx.OAuth2Error).Err.Status)
    return
  }
  defer token.Revoke() // This ensures the token is revoked before the function ends


  url := fmt.Sprintf("%s/spaces/%s/collections/%s/things/%s/properties",
    ApiUrl, Space, Collection, ThingID)


  client := resty.New()
  resp, err := client.R().
      SetAuthToken(token.AccessToken).
      SetBody(map[string]interface{}{"temperature": 27}).
      Put(url)
  if err != nil {
      w.WriteHeader(resp.StatusCode())
      w.Write(resp.Body())
      return
  }


  w.WriteHeader(http.StatusOK)
  w.Write(resp.Body())
}