azfunc

package module
v0.20.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 19, 2024 License: MIT Imports: 14 Imported by: 0

README

azfunc

Go Reference

Module to assist with Azure Functions with Custom handlers and Go

The purpose of this module is to provide functions and structures that helps with handling the incoming and outgoing requests to and from the Azure Function host when developing Azure Functions with Custom handlers and Go.

Contents

Why use this module?

After writing several Azure Functions with Custom handlers for Go I came to realize that the process of handling the incoming request payload from the Function host a tedious task (the overall structure and some content being escaped) and I found myself rewriting this request handling time and time again, every time with different ways and end result.

The idea of this module awoke to address this and to create a uniform way to do it across my current and future projects.

Install

Prerequisites

  • Go 1.18
go get github.com/KarlGW/azfunc

Example

HTTP trigger and HTTP output binding

Create hello-http/function.json with a HTTP trigger and HTTP output binding

{
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    },
  ]
}
package main

import (
    "github.com/KarlGW/azfunc"
    "github.com/KarlGW/azfunc/trigger"
)

func main() {
    app := azfunc.NewFunctionApp()

    app.AddFunction("hello-http", azfunc.HTTPTrigger(func(ctx *azfunc.Context, trigger *trigger.HTTP) error {
        // Parse the incoming trigger body into the custom type.
        var t test
        if err := trigger.Parse(&t); err != nil {
            // Send response back to caller.
            ctx.Output.HTTP().WriteHeader(http.StatusBadRequest)
            return nil
        }
        // Do something with t.
        // Create the response.
        ctx.Outputs.HTTP().WriteHeader(http.StatusOK)
        ctx.Outputs.HTTP().Header().Add("Content-Type", "application/json")
        ctx.Outputs.HTTP().Write([]byte(`{"message":"received"}`))
        return nil
    }))

    if err := app.Start(); err != nil {
        // Handle error.
    }
}

type test struct {
    Message string `json:"message"`
}

More examples with different triggers and output bindings can be found here.

Usage

The framework takes care of setting up the server and handlers, and you as a user register functions and bindings. Each function must have a corresponding function.json with binding specifications, in a folder named after the function. For more information about bindings, check out the documentation.

The trigger and output bindings registered to the FunctionApp must match with the names of the bindings in this file, the exception being with HTTP trigger and output bindings, req and res where this is handled without the names for convenience.

Creating this application structure can be done with ease with the help of the Function Core tools. In addition to scaffolding functions it can be used to run and test your functions locally.

An example on how to create a function with a HTTP trigger and a HTTP output binding (response) is provided further below.

Concepts

When working with the FunctionApp there are some concepts to understand and work with. The FunctionApp represents the entire Function App, and it is to this structure the functions (with their trigger and output bindings) that should be run are registered to. Each function that is registered contains a *azfunc.Context and a trigger.

The triggers is the triggering event and the data it contains, and the context contains output bindings (and writing to them), output error and logging.

Triggers (input bindings)

HTTP trigger

Triggered by an incoming HTTP event. The trigger contains the HTTP data (headers, url, query, params and body).

func(ctx *azfunc.Context, trigger *trigger.HTTP) error

Timer trigger

Triggered by a schedule. The trigger contains the timer data (next and last run etc).

func(ctx *azfunc.Context, trigger *trigger.Timer) error

Queue trigger

Triggered by a message to an Azure Queue Storage queue.

func(ctx *azfunc.Context, trigger *trigger.Queue) error

Service Bus trigger

Triggered by a message to an Azure Service Bus queue or topic subscription.

func(ctx *azfunc.Context, trigger *trigger.ServiceBus) error

Event Grid trigger

Triggered by an event to an Azure Event Grid topic subscription. Supports CloudEvents and Event Grid schemas.

func(ctx *azfunc.Context, trigger *trigger.EventGrid) error

Generic trigger

Generic trigger is a generic trigger can be used for all not yet supported triggers. The data it contains needs to be parsed into a struct matching the expected incoming payload.

func(ctx *azfunc.Context, trigger *trigger.Generic) error
Outputs (output bindings)

HTTP output

Writes an HTTP response back to the caller (only works together with an HTTP trigger).

Queue output

Writes a message to a queue in Azure Queue Storage.

Service Bus output

Writes a message to a queue or topic subscription in Azure Service Bus.

Event Grid output

Writes an event to Event Grid topic. Supports CloudEvents and Event Grid schemas.

Generic output

Generic binding is a generic binding that can be used for all not yet supported bindings.

Context

The context is the Function context, named so due to it being called so in the Azure Function implementation of other languages (foremost the old way of handling JavaScript/Node.js functions).

Assuming the *azfunc.Context is bound to the name ctx:

  • ctx.Log():
    • ctx.Log().Debug() for debug level logs.
    • ctx.Log().Error() for error level logs.
    • ctx.Log().Info() for info level logs.
    • ctx.Log().Warn() for warning level logs.
  • ctx.Binding("<binding-name>") - Provides access to the binding by name. If the binding it hasn't been provided together with the function at registration, it will created as a *bindings.Generic (will work as long as a binding with that same name is defined in the functions function.json).
  • ctx.Outputs:
    • ctx.Outputs.Log().Debug() for debug level logs.
    • ctx.Outputs.Log().Error() for error level logs.
    • ctx.Outputs.Log().Info() for info level logs.
    • ctx.Outputs.Log().Warn() for warning level logs.
    • ctx.Outputs.Log().Write() for custom string logs.
Error handling

The functions provided to the FunctionApp returns an error.

As an example: A function is triggered and run and encounters an error for one of it's calls. This error is deemed to be fatal and the function cannot carry on further. Thus we return the error.

func run(ctx *azfunc.Context, trigger *trigger.Queue) error {
    if err := someFunc(); err != nil {
        // This error is fatal, return ut to signal to the function host
        // that a non-recoverable error has occured.
        return err
    }
    // ... ...
    // ... ...
    return nil
}

An example of when an error is not regarded as fatal and not application breaking (like a malformed HTTP request), it can be handled like so:

func run(ctx *azfunc.Context, trigger *trigger.HTTP) error {
    var incoming IncomingRequest
    if err := trigger.Parse(&incoming); err != nil {
        // The incoming request body did not match the expected one,
        // this is equivalent of a HTTP 400 and should not signal to
        // the function host that it has failed, but still
        // stop further exection and return.
        ctx.Outputs.HTTP().WriteHeader(http.StatusBadRequest)
        return nil
    }
    // ... ...
    // ... ...
    return nil
}

Example with named return:

func run(ctx *azfunc.Context, trigger *trigger.HTTP) (err error) {
    var incoming IncomingRequest
    if err = trigger.Parse(&incoming); err != nil {
        // The incoming request body did not match the expected one,
        // this is equivalent of a HTTP 400 and should not signal to
        // the function host that it has failed, but still
        // stop further exection and return.
        ctx.Outputs.HTTP().WriteHeader(http.StatusBadRequest)
        return
    }
    // ... ...
    // ... ...
    return
}
Logging

There are two main approaches to logging, both provided in the azfunc.Context.

  • ctx.Log() - Logs to stdout (Debug, Info) and stderr (Error, Warning). These logs are written in "real time".
  • ctx.Outputs.Log() - Writes log entries to the output to the function host (invocation logs). It contains the same methods as ctx.Log() together with Write() which takes a custom string. These logs are written when the function has run and returned its response to the function host.

Both methods are visible in application insights.

TODO

  • Add more triggers and output bindings.
  • Add examples on using Managed Identities for trigger and output bindings (this is already supported).
  • Add better documentation for function.json structure and relations between properties and functionality.
  • Add generation and/or validation of host.json and function.json.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoFunction is returned when no function has been set to the
	// FunctionApp.
	ErrNoFunction = errors.New("at least one function must be set")
)

Functions

func New added in v0.17.0

func New(options ...FunctionAppOption) *functionApp

New creates and configures a FunctionApp.

func NewFunctionApp

func NewFunctionApp(options ...FunctionAppOption) *functionApp

NewFunctionApp creates and configures a FunctionApp.

Types

type Context

type Context struct {
	context.Context

	// Outputs contains output bindings.
	Outputs *outputs
	// contains filtered or unexported fields
}

Context represents the function context and contains output, bindings, services and clients.

func (*Context) Clients

func (c *Context) Clients() clients

Clients returns the clients set in the Context.

func (Context) Log added in v0.2.0

func (c Context) Log() Logger

Log returns the the logger configured for the function app.

func (*Context) Services

func (c *Context) Services() services

Services returns the services set in the Context.

func (*Context) SetLogger added in v0.3.0

func (c *Context) SetLogger(l logger)

SetLogger sets a logger to the Context. Should not be used in most use-cases due to it being set by the FunctionApp.

type EventGridTriggerFunc added in v0.14.0

type EventGridTriggerFunc func(ctx *Context, trigger *trigger.EventGrid) error

EventGridTriggerFunc represents an Event Grid trigger function to be executed by the function app.

type FunctionAppOption

type FunctionAppOption func(*functionApp)

FunctionAppOption is a function that sets options to a FunctionApp.

func WithClient

func WithClient(name string, client any) FunctionAppOption

WithClient sets the provided client to the FunctionApp. Can be called multiple times. If a client with the same name has been set it will be overwritten.

func WithDisableLogging added in v0.18.0

func WithDisableLogging() FunctionAppOption

WithDisableLogging disables logging for the FunctionApp.

func WithLogger

func WithLogger(log Logger) FunctionAppOption

WithLogger sets the provided Logger to the FunctionApp.

func WithService

func WithService(name string, service any) FunctionAppOption

WithService sets the provided service to the FunctionApp. Can be called multiple times. If a service with the same name has been set it will be overwritten.

type FunctionOption

type FunctionOption func(f *function)

FunctionOption sets options to the function.

func EventGridTrigger added in v0.14.0

func EventGridTrigger(name string, fn EventGridTriggerFunc, options ...trigger.EventGridOption) FunctionOption

EventGridTrigger takes the provided name and function and sets it as the function to be run by the trigger.

func GenericTrigger added in v0.15.0

func GenericTrigger(name string, fn GenericTriggerFunc, options ...trigger.GenericOption) FunctionOption

GenericTrigger takes the provided name and function and sets it as the function to be run by the trigger.

func HTTPTrigger

func HTTPTrigger(fn HTTPTriggerFunc, options ...trigger.HTTPOption) FunctionOption

HTTPTrigger takes the provided function and sets it as the function to be run by the trigger.

func QueueTrigger

func QueueTrigger(name string, fn QueueTriggerFunc, options ...trigger.QueueOption) FunctionOption

QueueTrigger takes the provided name and function and sets it as the function to be run by the trigger.

func ServiceBusTrigger added in v0.7.0

func ServiceBusTrigger(name string, fn ServiceBusTriggerFunc, options ...trigger.ServiceBusOption) FunctionOption

ServiceBusTrigger takes the provided name and function and sets it as the function to be run by the trigger.

func TimerTrigger

func TimerTrigger(fn TimerTriggerFunc, options ...trigger.TimerOption) FunctionOption

TimerTrigger takes the provided function and sets it as the function to be run by the trigger.

func WithOutput added in v0.17.0

func WithOutput(output outputable) FunctionOption

WithOutput sets the provided output binding to the function.

type GenericTriggerFunc added in v0.15.0

type GenericTriggerFunc func(ctx *Context, trigger *trigger.Generic) error

GenericTriggerFunc represents a generic function to be executed by the function app.

type HTTPTriggerFunc

type HTTPTriggerFunc func(ctx *Context, trigger *trigger.HTTP) error

HTTPTriggerFunc represents an HTTP trigger function to be executed by the function app.

type InvocationLogger added in v0.20.0

type InvocationLogger interface {
	Logger
	Write(msg string)
	Entries() []string
}

InvocationLogger is the interface that wraps around the methods Debug, Error, Info, Warn and Write. It is used to log to the function host.

type Logger added in v0.16.0

type Logger interface {
	Debug(msg string, args ...any)
	Error(msg string, args ...any)
	Info(msg string, args ...any)
	Warn(msg string, args ...any)
}

Logger is the interface that wraps around methods Debug, Error, Info and Warn. It is used to log to stdout and stderr.

func NewLogger added in v0.16.0

func NewLogger() Logger

NewLogger creates and returns a new Logger. Errors and warnings are written to stderr, while debug and info messages are written to stdout.

type QueueTriggerFunc added in v0.7.0

type QueueTriggerFunc func(ctx *Context, trigger *trigger.Queue) error

QueueTriggerFunc represents a Queue Storage trigger function to be exexuted by the function app.

type ServiceBusTriggerFunc added in v0.7.0

type ServiceBusTriggerFunc func(ctx *Context, trigger *trigger.ServiceBus) error

ServiceBusTriggerFunc represents a Service Bus trigger function to be exexuted by the function app.

type TimerTriggerFunc added in v0.2.0

type TimerTriggerFunc func(ctx *Context, trigger *trigger.Timer) error

TimerTriggerFunc represents a Timer trigger function tp be executed by the function app.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL