Go library

Created:
July 12, 2024
Updated:
December 4, 2024

Middlewares providing request and response validation against an OpenAPI spec at runtime, optionally integrating with the Firetail SaaS. Packages containing middleware for various different frameworks can be found in the middlewares directory, and examples of their use in examples.

Getting Started

Middleware for net/http

Get the middleware:



go get github.com/FireTail-io/firetail-go-lib/middlewares/http

Import it:



import firetail "github.com/FireTail-io/firetail-go-lib/middlewares/http"

Create a middleware using GetMiddleware; see the Options struct for all the available configurations:



firetailMiddleware, err := firetail.GetMiddleware(
	&firetail.Options{
		OpenapiSpecPath: path,
		LogApiKey:       apiToken,
	},
)
if err != nil {
	// Handle the err...
}

You will then have a func(next http.Handler) http.Handler, firetailMiddleware, which you can use to wrap a http.Handler just the same as with the middleware from net/http/middleware. This should also be suitable for Chi.

See the Go reference for the Options struct for documentation regarding the available options. For example, if you are using us.firetail.app you will need to set the LogsApiUrl to https://api.logging.us-east-2.prod.firetail.app/logs/bulk.

Tests

Automated testing is setup with the testing package, using github.com/stretchr/testify for shorthand assertions. You can run them with go test.

XML Support

The FireTail Go library does not come with XML request & response body decoding support out of the box. You will need to implement your own decoder as an openapi3filter.BodyDecoder and pass it to Firetail as part of the CustomBodyDecoders field of the firetail.Options struct. See the following example for a minimal XML decoder setup using sbabiv/xml2map:



middleware, err := firetail.GetMiddleware(&firetail.Options{
	OpenapiSpecPath: "./app-spec.yaml",
	CustomBodyDecoders: map[string]openapi3filter.BodyDecoder{
		"application/xml": func(r io.Reader, 
    h http.Header, sr *openapi3.SchemaRef,
    ef openapi3filter.EncodingFn) (interface{}, error) {
			return xml2map.NewDecoder(r).Decode()
		},
	},
})

Authentication

If you use securitySchemes in your OpenAPI specification, you will need to populate the firetail.Options struct's AuthCallbacks field with a callback for each security scheme implementing your authentication logic.

For example, for the following securitySchemes:


components:
  securitySchemes:
    MyBasicAuth:
      type: http
      scheme: basic

Your AuthCallback could look like this:


AuthCallbacks: map[string]func(context.Context, 
*openapi3filter.AuthenticationInput){
	"MyBasicAuth": func(ctx context.Context, 
  ai *openapi3filter.AuthenticationInput) error {
		token := ai.RequestValidationInput.Request.Header.Get("Authorization")
		return validateBasicAuthToken(token)
	},
},

Custom Auth Error Responses

To customise the errors returned by your application when a request fails to authenticate, you can pick up the errors returned by your AuthCallbacks in a custom ErrHandler. This allows you to, for example, add the WWW-Authenticate header on responses to requests that fail to validate against a basic auth security requirement.