Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: init declarative functions go (#92)
Declarative functions interface for the Go Functions Framework. ## Example usage ### main.go Sample main package used for local development only. ```go package main import ( "os" "github.com/GoogleCloudPlatform/functions-framework-go/funcframework" ) func main() { port := "8080" if envPort := os.Getenv("PORT"); envPort != "" { port = envPort } if err := funcframework.Start(port); err != nil { log.Fatalf("Failed to start functions framework: %v", err) } } ``` ### function.go Sample declarative function, registered in `init`. ```go package function import ( "net/http" "os" "github.com/GoogleCloudPlatform/functions-framework-go/funcframework" ) func HelloWorld(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, World!")) } func init() { // Register your function named "hello" funcframework.HTTPFunction("hello", HelloWorld) } ``` ## Features - Exposes new functions `HTTP` and `CloudEvent` that allows you to declaratively register a function with a given name. - Creates a function registry (similar to python and Node). I expect the registry to be more useful as we add more features to declarative functions. - Adds sample declarative functions for conformance tests. - Adds sample runnable functions in `testdata`. - Adds basic docs in the `README.md`. ### Example tests - `go run testdata/declarative/http/main.go` - `2021/10/28 15:38:50 Listening to function "http" at http://localhost:8080/ Serving function...` - `go run testdata/declarative/cloudevent/main.go` - `2021/10/28 15:40:54 Listening to function "cloudevent" at http://localhost:8080/ Serving function...` ### Example conformance functions ``` FUNCTION_TARGET=declarativeHTTP go run testdata/conformance/cmd/declarative/main.go FUNCTION_TARGET=declarativeCE go run testdata/conformance/cmd/declarative/main.go ``` I'm not an expert in Go, so feel free to suggest any changes!
- Loading branch information
Showing
9 changed files
with
297 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package registry | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
|
||
cloudevents "github.com/cloudevents/sdk-go/v2" | ||
) | ||
|
||
// A declaratively registered function | ||
type RegisteredFunction struct { | ||
Name string // The name of the function | ||
CloudEventFn func(context.Context, cloudevents.Event) error // Optional: The user's CloudEvent function | ||
HTTPFn func(http.ResponseWriter, *http.Request) // Optional: The user's HTTP function | ||
} | ||
|
||
var ( | ||
function_registry = map[string]RegisteredFunction{} | ||
) | ||
|
||
// Registers a HTTP function with a given name | ||
func RegisterHTTP(name string, fn func(http.ResponseWriter, *http.Request)) error { | ||
if _, ok := function_registry[name]; ok { | ||
return fmt.Errorf("function name already registered: %s", name) | ||
} | ||
function_registry[name] = RegisteredFunction{ | ||
Name: name, | ||
CloudEventFn: nil, | ||
HTTPFn: fn, | ||
} | ||
return nil | ||
} | ||
|
||
// Registers a CloudEvent function with a given name | ||
func RegisterCloudEvent(name string, fn func(context.Context, cloudevents.Event) error) error { | ||
if _, ok := function_registry[name]; ok { | ||
return fmt.Errorf("function name already registered: %s", name) | ||
} | ||
function_registry[name] = RegisteredFunction{ | ||
Name: name, | ||
CloudEventFn: fn, | ||
HTTPFn: nil, | ||
} | ||
return nil | ||
} | ||
|
||
// Gets a registered function by name | ||
func GetRegisteredFunction(name string) (RegisteredFunction, bool) { | ||
fn, ok := function_registry[name] | ||
return fn, ok | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Copyright 2021 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package registry | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"testing" | ||
|
||
cloudevents "github.com/cloudevents/sdk-go/v2" | ||
) | ||
|
||
func TestRegisterHTTP(t *testing.T) { | ||
RegisterHTTP("httpfn", func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprint(w, "Hello World!") | ||
}) | ||
|
||
fn, ok := GetRegisteredFunction("httpfn") | ||
if !ok { | ||
t.Fatalf("Expected function to be registered") | ||
} | ||
if fn.Name != "httpfn" { | ||
t.Errorf("Expected function name to be 'httpfn', got %s", fn.Name) | ||
} | ||
} | ||
|
||
func TestRegisterCE(t *testing.T) { | ||
RegisterCloudEvent("cefn", func(context.Context, cloudevents.Event) error { | ||
return nil | ||
}) | ||
|
||
fn, ok := GetRegisteredFunction("cefn") | ||
if !ok { | ||
t.Fatalf("Expected function to be registered") | ||
} | ||
if fn.Name != "cefn" { | ||
t.Errorf("Expected function name to be 'cefn', got %s", fn.Name) | ||
} | ||
} | ||
|
||
func TestRegisterMultipleFunctions(t *testing.T) { | ||
if err := RegisterHTTP("multifn1", func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprint(w, "Hello World!") | ||
}); err != nil { | ||
t.Error("Expected \"multifn1\" function to be registered") | ||
} | ||
if err := RegisterHTTP("multifn2", func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprint(w, "Hello World 2!") | ||
}); err != nil { | ||
t.Error("Expected \"multifn2\" function to be registered") | ||
} | ||
if err := RegisterCloudEvent("multifn3", func(context.Context, cloudevents.Event) error { | ||
return nil | ||
}); err != nil { | ||
t.Error("Expected \"multifn3\" function to be registered") | ||
} | ||
} | ||
|
||
func TestRegisterMultipleFunctionsError(t *testing.T) { | ||
if err := RegisterHTTP("samename", func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprint(w, "Hello World!") | ||
}); err != nil { | ||
t.Error("Expected no error registering function") | ||
} | ||
|
||
if err := RegisterHTTP("samename", func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprint(w, "Hello World 2!") | ||
}); err == nil { | ||
t.Error("Expected error registering function with same name") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright 2021 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Binary that serves the HTTP conformance test function. | ||
package main | ||
|
||
import ( | ||
"log" | ||
"os" | ||
|
||
"github.com/GoogleCloudPlatform/functions-framework-go/funcframework" | ||
_ "github.com/GoogleCloudPlatform/functions-framework-go/testdata/conformance/function" | ||
) | ||
|
||
// Main function used for testing only: | ||
// FUNCTION_TARGET=declarativeHTTP go run testdata/conformance/cmd/declarative/main.go | ||
// FUNCTION_TARGET=declarativeCloudEvent go run testdata/conformance/cmd/declarative/main.go | ||
func main() { | ||
port := "8080" | ||
if envPort := os.Getenv("PORT"); envPort != "" { | ||
port = envPort | ||
} | ||
if err := funcframework.Start(port); err != nil { | ||
log.Fatalf("Failed to start functions framework: %v", err) | ||
} | ||
} |
Oops, something went wrong.