g8

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 21, 2023 License: MIT Imports: 16 Imported by: 0

README

g8

Provides the following utilities to simplify working with AWS lambda and API Gateway.

  • Simple handler interface
  • HTTP request parsing with JSON support and request body validation
  • HTTP response writer with JSON support
  • Custom error type with JSON support
  • Logging unhandled errors with a stack trace
  • Correlation ID
  • New Relic integration

Request body parsing

Use the bind method to unmarshal the response body to a struct

type requestBody struct {
	Name   string `json:"name"`
}

handler := func(c *g8.APIGatewayProxyContext) error {
	var b requestBody
	err := c.Bind(&b)
	if err != nil {
		return err
	}

	...

	c.JSON(http.StatusOK, responseBody)
}

Request body validation

Implement the Validate method on the struct

type requestBody struct {
	Name   string `json:"name"`
	Status string `json:"status"`
}

func (b body) Validate() error {
	if b.Status == "" {
		return errors.New("status empty")
	}
	return nil
}

handler := func(c *g8.APIGatewayProxyContext) error {
	var b requestBody
	err := c.Bind(&b)
	if err != nil {
		// validation error would be returned here
		return err
	}
	
	...
	
	c.JSON(http.StatusOK, responseBody)
}

API Gateway Lambda Authorizer Handlers

You are able to define handlers for Lambda Authorizer (previously known as custom authorizers) using g8. Here is an example:

handler := g8.APIGatewayCustomAuthorizerHandlerWithNewRelic(
    func(c *APIGatewayCustomAuthorizerContext) error{
        c.Response.SetPrincipalID("some-principal-ID")

        c.Response.AllowAllMethods()
        // other examples:
        // c.Response.DenyAllMethods()
        // c.Response.AllowMethod(Post, "/pets/*")
        return nil
    },
    g8.HandlerConfig{
        ...
    },
)

lambda.StartHandler(handler)

Response writing

There are several methods provided to simplify writing HTTP responses.

handler := func(c *g8.APIGatewayProxyContext) error {
    ...
    c.JSON(http.StatusOK, responseBody)
}

Errors

Go Errors

Returning Go errors to the error response writer will log the error and respond with an internal server error

handler := func(c *g8.APIGatewayProxyContext) error {
	...
	return errors.New("something went wrong")
}
Custom Errors

You can return custom g8 errors and also map them to HTTP status codes

handler := func(c *g8.APIGatewayProxyContext) error {
    ...
    return g8.Err{
        Status: http.StatusBadRequest,
        Code:   "SOME_CLIENT_ERROR",
        Detail: "Invalid param",
    }
}

Writes the following response, with status code 400

{
    "code": "SOME_CLIENT_ERROR",
    "detail": "Invalid param"
}
Logging stack traces

Unhandled errors are logged automatically with a stack trace if the error is wrapped by eris.

The new version of eris handles errors differently and produce a different JSON response compared to the previous version, additionally all errors now produce a JSON response, please fully test these changes.

eris.Wrapf(err, "failed to send offers to user id: %v", userID)
HTTP Adaptor

In order to facilitate the serving of HTTP and the development of g8.APIGatewayProxyHandler lambdas, engineers can utilise the NewHTTPHandler function. This function is particularly beneficial for local development and pact provider testing, as it assists in verifying that an API provider is adhering to the pacts established by its clients. By using this feature, engineers can ensure that their API is functioning correctly and meeting the necessary expectations of its users.

Example
g8.NewHTTPHandler(LambdaHandlerEndpoints{
    g8.LambdaHandler{
        Handler:     func(c *g8.APIGatewayProxyContext) error {
            c.JSON(http.StatusOK, "success")
            return nil
        },
        Method:      http.MethodGet,
        PathPattern: "/full/url/path/{var1}/{var2}",
    },
    g8.LambdaHandler{
        Handler:     func(c *g8.APIGatewayProxyContext) error {
            return errors.New("some error")
        },
        Method:      http.MethodPost,
        PathPattern: "/another/full/url/path/{var1}",
    },
}, 8080)
Requirements
  • Go 1.19+

Documentation

Index

Constants

View Source
const (
	WelcomeMessage      = "G8 HTTP server is running on port"
	UnhandledErrMessage = "unhandled error: "
)
View Source
const All = "*"

Variables

View Source
var ErrInternalServer = Err{
	Status: http.StatusInternalServerError,
	Code:   "INTERNAL_SERVER_ERROR",
	Detail: "Internal server error",
}
View Source
var ErrInvalidBody = Err{
	Status: http.StatusBadRequest,
	Code:   "INVALID_REQUEST_BODY",
	Detail: "Invalid request body",
}

Functions

func APIGatewayCustomAuthorizerHandler added in v0.1.4

APIGatewayCustomAuthorizerHandler fd

func APIGatewayCustomAuthorizerHandlerWithNewRelic added in v0.1.4

func APIGatewayCustomAuthorizerHandlerWithNewRelic(h APIGatewayCustomAuthorizerHandlerFunc, conf HandlerConfig) lambda.Handler

func APIGatewayProxyHandlerWithNewRelic

func APIGatewayProxyHandlerWithNewRelic(h APIGatewayProxyHandlerFunc, conf HandlerConfig) lambda.Handler

func CloudWatchHandler added in v0.1.1

func CloudWatchHandlerWithNewRelic added in v0.1.1

func CloudWatchHandlerWithNewRelic(h CloudWatchHandlerFunc, conf HandlerConfig) lambda.Handler

func DynamoDbHandler added in v0.1.5

func DynamoDbHandlerWithNewRelic added in v0.1.5

func DynamoDbHandlerWithNewRelic(h DynamoHandlerFunc, conf HandlerConfig) lambda.Handler

func LambdaAdapter added in v0.2.2

func LambdaAdapter(l LambdaHandler) func(http.ResponseWriter, *http.Request)

LambdaAdapter converts a LambdaHandler into a http.HandlerFunc.

func NewAuthorizerResponse added in v0.1.4

func NewAuthorizerResponse() events.APIGatewayCustomAuthorizerResponse

func NewHTTPHandler added in v0.2.2

func NewHTTPHandler(lambdaEndpoints LambdaHandlerEndpoints, portNumber int)

NewHTTPHandler creates a new HTTP server that listens on the given port.

func S3Handler

func S3Handler(h S3HandlerFunc, conf HandlerConfig) func(context.Context, events.S3Event) error

func S3HandlerWithNewRelic

func S3HandlerWithNewRelic(h S3HandlerFunc, conf HandlerConfig) lambda.Handler

func SQSHandlerWithNewRelic

func SQSHandlerWithNewRelic(h SQSHandlerFunc, conf HandlerConfig) lambda.Handler

func StepHandler added in v0.2.1

func StepHandler(h StepHandlerFunc, conf HandlerConfig) func(context.Context, StepEvent) (StepEvent, error)

func StepHandlerWithNewRelic added in v0.2.1

func StepHandlerWithNewRelic(h StepHandlerFunc, conf HandlerConfig) lambda.Handler

Types

type APIGatewayCustomAuthorizerContext added in v0.1.4

type APIGatewayCustomAuthorizerContext struct {
	Context       context.Context
	Request       events.APIGatewayCustomAuthorizerRequestTypeRequest
	Response      events.APIGatewayCustomAuthorizerResponse
	Logger        zerolog.Logger
	NewRelicTx    newrelic.Transaction
	CorrelationID string
	// contains filtered or unexported fields
}

APIGatewayCustomAuthorizerContext the context for a request for Custom Authorizer

func (*APIGatewayCustomAuthorizerContext) AddNewRelicAttribute added in v0.1.4

func (c *APIGatewayCustomAuthorizerContext) AddNewRelicAttribute(key string, val interface{})

func (*APIGatewayCustomAuthorizerContext) AllowAllMethods added in v0.1.4

func (c *APIGatewayCustomAuthorizerContext) AllowAllMethods()

func (*APIGatewayCustomAuthorizerContext) AllowMethod added in v0.1.4

func (c *APIGatewayCustomAuthorizerContext) AllowMethod(verb, resource string)

func (*APIGatewayCustomAuthorizerContext) DenyAllMethods added in v0.1.4

func (c *APIGatewayCustomAuthorizerContext) DenyAllMethods()

func (*APIGatewayCustomAuthorizerContext) DenyMethod added in v0.1.4

func (c *APIGatewayCustomAuthorizerContext) DenyMethod(verb, resource string)

func (*APIGatewayCustomAuthorizerContext) SetPrincipalID added in v0.1.4

func (c *APIGatewayCustomAuthorizerContext) SetPrincipalID(principalID string)

type APIGatewayCustomAuthorizerHandlerFunc added in v0.1.4

type APIGatewayCustomAuthorizerHandlerFunc func(c *APIGatewayCustomAuthorizerContext) error

APIGatewayCustomAuthorizerHandlerFunc to populate

type APIGatewayProxyContext

type APIGatewayProxyContext struct {
	Context       context.Context
	Request       events.APIGatewayProxyRequest
	Response      events.APIGatewayProxyResponse
	Logger        zerolog.Logger
	NewRelicTx    newrelic.Transaction
	CorrelationID string
}

func (*APIGatewayProxyContext) AddNewRelicAttribute

func (c *APIGatewayProxyContext) AddNewRelicAttribute(key string, val interface{})

func (*APIGatewayProxyContext) Bind

func (c *APIGatewayProxyContext) Bind(v interface{}) error

func (*APIGatewayProxyContext) GetCookie added in v0.1.3

func (c *APIGatewayProxyContext) GetCookie(name string) (http.Cookie, bool)

GetCookie retrieves the cookie with the given name

func (*APIGatewayProxyContext) GetHeader added in v0.1.3

func (c *APIGatewayProxyContext) GetHeader(name string) string

GetHeader retrieves the header value by name. It canonicalizes headers to ensure that values can be accessed in a case insensitive manner

func (*APIGatewayProxyContext) JSON

func (c *APIGatewayProxyContext) JSON(statusCode int, body interface{}) error

type APIGatewayProxyHandlerFunc

type APIGatewayProxyHandlerFunc func(c *APIGatewayProxyContext) error

type CloudWatchContext added in v0.1.1

type CloudWatchContext struct {
	Context       context.Context
	Event         events.CloudWatchEvent
	Logger        zerolog.Logger
	NewRelicTx    newrelic.Transaction
	CorrelationID string
}

func (*CloudWatchContext) AddNewRelicAttribute added in v0.1.1

func (c *CloudWatchContext) AddNewRelicAttribute(key string, val interface{})

type CloudWatchHandlerFunc added in v0.1.1

type CloudWatchHandlerFunc func(c *CloudWatchContext) (LambdaResult, error)

type DynamoDbContext added in v0.1.5

type DynamoDbContext struct {
	Context       context.Context
	EventRecord   events.DynamoDBEventRecord
	Logger        zerolog.Logger
	NewRelicTx    newrelic.Transaction
	CorrelationID string
}

func (*DynamoDbContext) AddNewRelicAttribute added in v0.1.5

func (c *DynamoDbContext) AddNewRelicAttribute(key string, val interface{})

type DynamoHandlerFunc added in v0.1.5

type DynamoHandlerFunc func(c *DynamoDbContext) error

type Effect added in v0.1.4

type Effect int
const (
	Allow Effect = iota
	Deny
)

func (Effect) String added in v0.1.4

func (e Effect) String() string

type Err

type Err struct {
	Status int    `json:"-"`
	Code   string `json:"code"`
	Detail string `json:"detail"`
}

func ErrValidation

func ErrValidation(detail string) Err

func (Err) Error

func (err Err) Error() string

type HandlerConfig

type HandlerConfig struct {
	AppName      string
	FunctionName string
	EnvName      string
	BuildVersion string
	Logger       zerolog.Logger
	NewRelicApp  newrelic.Application
}

type LambdaHandler added in v0.2.2

type LambdaHandler struct {
	Handler     any
	Method      string
	PathPattern string
}

type LambdaHandlerEndpoints added in v0.2.2

type LambdaHandlerEndpoints []LambdaHandler

type LambdaResult added in v0.1.2

type LambdaResult interface{}

type S3Context

type S3Context struct {
	Context       context.Context
	EventRecord   events.S3EventRecord
	Logger        zerolog.Logger
	NewRelicTx    newrelic.Transaction
	CorrelationID string
}

func (*S3Context) AddNewRelicAttribute

func (c *S3Context) AddNewRelicAttribute(key string, val interface{})

type S3HandlerFunc

type S3HandlerFunc func(c *S3Context) error

type SQSContext

type SQSContext struct {
	Context       context.Context
	Message       events.SQSMessage
	Logger        zerolog.Logger
	NewRelicTx    newrelic.Transaction
	CorrelationID string
}

func (*SQSContext) AddNewRelicAttribute

func (c *SQSContext) AddNewRelicAttribute(key string, val interface{})

func (*SQSContext) Bind

func (c *SQSContext) Bind(v interface{}) error

type SQSHandlerFunc

type SQSHandlerFunc func(c *SQSContext) error

type SQSMessageEnvelope

type SQSMessageEnvelope struct {
	Data interface{}     `json:"data"`
	Meta *SQSMessageMeta `json:"meta"`
}

type SQSMessageMeta

type SQSMessageMeta struct {
	CorrelationID string `json:"correlation_id"`
}

type StepContext added in v0.2.1

type StepContext struct {
	Context       context.Context
	Event         StepEvent
	Logger        zerolog.Logger
	NewRelicTx    newrelic.Transaction
	CorrelationID string
}

func (*StepContext) AddNewRelicAttribute added in v0.2.1

func (c *StepContext) AddNewRelicAttribute(key string, val interface{})

type StepEvent added in v0.2.1

type StepEvent interface{}

type StepHandlerFunc added in v0.2.1

type StepHandlerFunc func(c *StepContext) (StepEvent, error)

type Validatable

type Validatable interface {
	Validate() error
}

Jump to

Keyboard shortcuts

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