Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions TODO.md

This file was deleted.

62 changes: 62 additions & 0 deletions go/echo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Go HTTP Function

Welcome to your new Go Function! The boilerplate function code can be found in
[`handle.go`](handle.go). This Function responds to HTTP requests.

## Development

Develop new features by adding a test to [`handle_test.go`](handle_test.go) for
each feature, and confirm it works with `go test`.

Update the running analog of the function using the `func` CLI or client
library, and it can be invoked from your browser or from the command line:

```console
curl http://myfunction.example.com/
```

### Import Private Go Modules
If you want to use a module that is in a private `git` repository,
you can do it by mounting credentials and by setting appropriate environment variable.

This is done by setting the `build.volumes` and `build.buildEnvs` properties in the `func.yaml` config file.

#### pack
For the `pack` builder have to use [paketo bindings](https://github.com/paketo-buildpacks/git?tab=readme-ov-file#bindings):
```yaml
# $schema: https://raw.githubusercontent.com/knative/func/refs/heads/main/schema/func_yaml-schema.json
specVersion: 0.36.0
name: go-fn
runtime: go
created: 2025-03-17T02:02:34.196208671+01:00
build:
buildEnvs:
- name: GOPRIVATE
value: example.com
- name: SERVICE_BINDING_ROOT
value: /bindings
volumes:
- hostPath: /tmp/git-binding
path: /bindings/git-binding
```

#### s2i
For the `s2i` builder you have to mount credentials in `.netrc` format.
```yaml
# $schema: https://raw.githubusercontent.com/knative/func/refs/heads/main/schema/func_yaml-schema.json
specVersion: 0.36.0
name: go-fn
runtime: go
created: 2025-03-17T02:02:34.196208671+01:00
build:
buildEnvs:
- name: GOPRIVATE
value: example.com
volumes:
- hostPath: /home/jdoe/.netrc
path: /opt/app-root/src/.netrc
```

For more, see [the complete documentation]('https://github.com/knative/func/tree/main/docs')


3 changes: 3 additions & 0 deletions go/echo/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module function

go 1.21
26 changes: 26 additions & 0 deletions go/echo/handle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package function

import (
"fmt"
"net/http"
"net/http/httputil"
)

// Handle an HTTP Request.
func Handle(w http.ResponseWriter, r *http.Request) {
/*
* YOUR CODE HERE
*
* Try running `go test`. Add more test as you code in `handle_test.go`.
*/

dump, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

fmt.Println("Received request")
fmt.Printf("%q\n", dump)
fmt.Fprintf(w, "%q", dump)
}
25 changes: 25 additions & 0 deletions go/echo/handle_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package function

import (
"net/http"
"net/http/httptest"
"testing"
)

// TestHandle ensures that Handle executes without error and returns the
// HTTP 200 status code indicating no errors.
func TestHandle(t *testing.T) {
var (
w = httptest.NewRecorder()
req = httptest.NewRequest("GET", "http://example.com/test", nil)
res *http.Response
)

Handle(w, req)
res = w.Result()
defer res.Body.Close()

if res.StatusCode != 200 {
t.Fatalf("unexpected response code: %v", res.StatusCode)
}
}
1 change: 1 addition & 0 deletions node/echo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
126 changes: 126 additions & 0 deletions node/echo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Node.js HTTP Function

Welcome to your new Node.js function project! The boilerplate function code can be found in [`index.js`](./index.js). This function will respond to incoming HTTP GET and POST requests. This example function is written synchronously, returning a raw value. If your function performs any asynchronous execution, you can safely add the `async` keyword to the function, and return a `Promise`.

## Local execution

After executing `npm install`, you can run this function locally by executing `npm run local`.

The runtime will expose three endpoints.

* `/` The endpoint for your function.
* `/health/readiness` The endpoint for a readiness health check
* `/health/liveness` The endpoint for a liveness health check

The parameter provided to the function endpoint at invocation is a `Context` object containing HTTP request information.

```js
function handleRequest(context) {
const log = context.log;
log.info(context.httpVersion);
log.info(context.method); // the HTTP request method (only GET or POST supported)
log.info(context.query); // if query parameters are provided in a GET request
log.info(context.body); // contains the request body for a POST request
log.info(context.headers); // all HTTP headers sent with the event
}
```

The health checks can be accessed in your browser at [http://localhost:8080/health/readiness]() and [http://localhost:8080/health/liveness](). You can use `curl` to `POST` an event to the function endpoint:

```console
curl -X POST -d '{"hello": "world"}' \
-H'Content-type: application/json' \
http://localhost:8080
```

The readiness and liveness endpoints use [overload-protection](https://www.npmjs.com/package/overload-protection) and will respond with `HTTP 503 Service Unavailable` with a `Client-Retry` header if your function is determined to be overloaded, based on the memory usage and event loop delay.

## The Function Interface

The `index.js` file may export a single function or a `Function`
object. The `Function` object allows developers to add lifecycle hooks for
initialization and shutdown, as well as providing a way to implement custom
health checks.

The `Function` interface is defined as:

```typescript
export interface Function {
// The initialization function, called before the server is started
// This function is optional and should be synchronous.
init?: () => any;

// The shutdown function, called after the server is stopped
// This function is optional and should be synchronous.
shutdown?: () => any;

// The liveness function, called to check if the server is alive
// This function is optional and should return 200/OK if the server is alive.
liveness?: HealthCheck;

// The readiness function, called to check if the server is ready to accept requests
// This function is optional and should return 200/OK if the server is ready.
readiness?: HealthCheck;

logLevel?: LogLevel;

// The function to handle HTTP requests
handle: CloudEventFunction | HTTPFunction;
}
```

## Handle Signature

The HTTP function interface is defined as:

```typescript
interface HTTPFunction {
(context: Context, body?: IncomingBody): HTTPFunctionReturn;
}
```

Where the `IncomingBody` is either a string, a Buffer, a JavaScript object, or undefined, depending on what was supplied in the HTTP POST message body. The `HTTTPFunctionReturn` type is defined as:

```typescript
type HTTPFunctionReturn = Promise<StructuredReturn> | StructuredReturn | ResponseBody | void;
```

Where the `StructuredReturn` is a JavaScript object with the following properties:

```typescript
interface StructuredReturn {
statusCode?: number;
headers?: Record<string, string>;
body?: ResponseBody;
}
```

If the function returns a `StructuredReturn` object, then the `statusCode` and `headers` properties are used to construct the HTTP response. If the `body` property is present, it is used as the response body. If the function returns `void` or `undefined`, then the response body is empty.

The `ResponseBody` is either a string, a JavaScript object, or a Buffer. JavaScript objects will be serialized as JSON. Buffers will be sent as binary data.

### Health Checks

The `Function` interface also allows for the addition of a `liveness` and `readiness` function. These functions are used to implement health checks for the function. The `liveness` function is called to check if the function is alive. The `readiness` function is called to check if the function is ready to accept requests. If either of these functions returns a non-200 status code, then the function is considered unhealthy.

A health check function is defined as:

```typescript
/**
* The HealthCheck interface describes a health check function,
* including the optional path to which it should be bound.
*/
export interface HealthCheck {
(request: Http2ServerRequest, reply: Http2ServerResponse): any;
path?: string;
}
```

By default, the health checks are bound to the `/health/liveness` and `/health/readiness` paths. You can override this by setting the `path` property on the `HealthCheck` object, or by setting the `LIVENESS_URL` and `READINESS_URL` environment variables.
## Testing

This function project includes a [unit test](./test/unit.js) and an [integration test](./test/integration.js). All `.js` files in the test directory are run.

```console
npm test
```
39 changes: 39 additions & 0 deletions node/echo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Your HTTP handling function, invoked with each request. This is an example
* function that echoes its input to the caller, and returns an error if
* the incoming request is something other than an HTTP POST or GET.
*
* It can be invoked with 'func invoke'
* It can be tested with 'npm test'
*
* @param {Context} context - A context object.
* @param {object} context.query - The query string deserialized as an object, if any.
* @param {object} context.log - Logging object with methods for 'info', 'warn', 'error', etc.
* @param {object} context.headers - The HTTP request headers.
* @param {string} context.method - The HTTP request method.
* @param {string} context.httpVersion - The HTTP protocol version.
* @param {object} body - The request body if any.
* @returns {object} HTTP response object with body, query, or error status.
*
* See: https://github.com/knative/func/blob/main/docs/function-developers/nodejs.md#the-context-object
*/
const handle = async (context, body) => {
// YOUR CODE HERE
context.log.info("query", context.query);
context.log.info("body", body);

// If the request is an HTTP POST, the context will contain the request body
if (context.method === 'POST') {
return { body };
} else if (context.method === 'GET') {
// If the request is an HTTP GET, the context will include a query string, if it exists
return {
query: context.query,
}
} else {
return { statusCode: 405, statusMessage: 'Method not allowed' };
}
}

// Export the function
module.exports = { handle };
Loading
Loading