Change function Main signature to match OpenWhisk base Conformance JSON IN<->OUT
csantanapr opened this issue · 5 comments
Currently the main function signature takes 1 input (raw []bytes) and returns 2 outputs (raw [] bytes, error)
I think is ok to have alternative signatures like we do for Swift and Codable, and 1 input, an 0 output.
This is done to adapt better with developer experience and the language idioms
But the base OW signature is the building block and the first one to be offer.
Currently the signature is
func Main(event json.RawMessage) (json.RawMessage, error)
In example:
// Main is the function implementing the action
func Main(event json.RawMessage) (json.RawMessage, error) {
// decode the json
var obj map[string]interface{}
json.Unmarshal(event, &obj)
// do your work
name, ok := obj["name"].(string)
if !ok {
name = "Stranger"
}
msg := map[string]string{"message": ("Hello, " + name + "!")}
// log in stdout or in stderr
log.Printf("name=%s\n", name)
// encode the result back in json
return json.Marshal(msg)
}
This also has a drawback that dev will be 99% will be unmarshalling the input and the output.
in the way in
var obj map[string]interface{}
json.Unmarshal(event, &obj)
in the way out
json.Marshal(msg)
I propose we start with this base signature instead:
func Main(params map[string]interface{}) map[string]interface{}
in example much simple for developer to deal with
func Main(params map[string]interface{}) map[string]interface{} {
name, ok := params["name"].(string)
if !ok {
name = "World"
}
var result = make(map[string]interface{})
result["body"] = "Hello " + name
return result
}
to return error same base API for OW, return a error
key in the out
...
myError["message"] = "My error msg here for OW to bubble up"
result["error"] = myError
return result
As secondary signature can be added to have a variation that return 2 results in output to be more golang friendly
func Main(params map[string]interface{}) (map[string]interface{}, error)
So proposal would be to the following signatures
func Main(params map[string]interface{}) map[string]interface{}
func Main(params map[string]interface{}) (map[string]interface{}, error)
As we get this out in to the main default deployment as a kind --kind golang:1.10
We could get feedback that other signatures to be added that include some sort of streams using golang channels.
Here is a reference to a web server action I used while experimenting with the new signature
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func parsedInput(r *http.Request) map[string]interface{} {
body, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()
var payload map[string]interface{}
json.Unmarshal(body, &payload)
return payload["value"].(map[string]interface{})
}
func runHandler(w http.ResponseWriter, r *http.Request) {
out, _ := json.Marshal(Main(parsedInput(r)))
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, string(out))
}
func initHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{"ok":true}`)
}
// Main my cool serverless function
func Main(params map[string]interface{}) map[string]interface{} {
name, ok := params["name"].(string)
if !ok {
name = "World"
}
var result = make(map[string]interface{})
result["body"] = "Hello " + name
return result
}
func main() {
http.HandleFunc("/init", initHandler)
http.HandleFunc("/run", runHandler)
http.ListenAndServe(":8080", nil)
}
Ok I want to check how this can be done. A simple way would be to use a regular expression to recognize the signature But I am trying to find better ways. Assign to me (tag it sciabarracom)
Changed the main signature please close this bug
This is fixed now