fuego

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Nov 30, 2024 License: MIT Imports: 31 Imported by: 0

README

Fuego Logo

Fuego 🔥

Go Reference Go Report Card Coverage Status Discord Gophers

The framework for busy Go developers

Build your API or web application in minutes!

Go framework generating OpenAPI documentation from code. Inspired by Nest, built for Go developers.

Also empowers html/template, a-h/templ and maragudk/gomponents: see the example - actually running in prod!

Sponsors

Fuego is proudly sponsored by Zuplo, that provides a Fuego integration!

Fuego Logo

Zuplo allows you to secure your Fuego API, scale it globally, generate documentation from your OpenAPI, and monetize your users.

Why Fuego?

Chi, Gin, Fiber and Echo are great frameworks. But since they were designed a long time ago, their current API does not allow them to deduce OpenAPI types from signatures, things that are now possible with generics. Fuego offers a lot of "modern Go based" features that make it easy to develop APIs and web applications.

Features

  • OpenAPI: Fuego automatically generates OpenAPI documentation from code - not from comments nor YAML files!
  • 100% net/http compatible (no lock-in): Fuego is built on top of net/http, so you can use any http.Handler middleware or handler! Fuego also supports log/slog, context and html/template.
  • Routing: Fuego router is based on Go 1.22 net/http, with grouping and middleware support
  • Serialization/Deserialization: Fuego automatically serializes and deserializes JSON, XML and HTML Forms based on user-provided structs (or not, if you want to do it yourself)
  • Validation: Fuego provides a simple and fast validator based on go-playground/validator
  • Transformation: easily transform your data by implementing the fuego.InTransform and fuego.OutTransform interfaces - also useful for custom validation
  • Middlewares: easily add a custom net/http middleware or use the provided middlewares.
  • Error handling: Fuego provides centralized error handling with the standard RFC 9457.
  • Rendering: Fuego provides a simple and fast rendering system based on html/template - you can still also use your own template system like templ or gomponents

Examples

Hello World
package main

import "github.com/go-fuego/fuego"

func main() {
	s := fuego.NewServer()

	fuego.Get(s, "/", func(c fuego.ContextNoBody) (string, error) {
		return "Hello, World!", nil
	})

	s.Run()
}
Simple POST
package main

import "github.com/go-fuego/fuego"

type MyInput struct {
	Name string `json:"name" validate:"required"`
}

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

func main() {
	s := fuego.NewServer()

	// Automatically generates OpenAPI documentation for this route
	fuego.Post(s, "/", func(c *fuego.ContextWithBody[MyInput]) (MyOutput, error) {
		body, err := c.Body()
		if err != nil {
			return MyOutput{}, err
		}

		return MyOutput{
			Message: "Hello, " + body.Name,
		}, nil
	})

	s.Run()
}
With transformation & custom validation
type MyInput struct {
	Name string `json:"name" validate:"required"`
}

// Will be called just before returning c.Body()
func (r *MyInput) InTransform(context.Context) error {
	r.Name = strings.ToLower(r.Name)

	if r.Name == "fuego" {
		return errors.New("fuego is not a valid name for this input")
	}

	return nil
}

More OpenAPI documentation
package main

import (
	"github.com/go-fuego/fuego"
	"github.com/go-fuego/fuego/option"
	"github.com/go-fuego/fuego/param"
)

func main() {
	s := fuego.NewServer()

	// Custom OpenAPI options
	fuego.Post(s, "/", myController
		option.Description("This route does something..."),
		option.Summary("This is my summary"),
		option.Tags("MyTag"), // A tag is set by default according to the return type (can be deactivated)
		option.Deprecated(), // Marks the route as deprecated in the OpenAPI spec

		option.Query("name", "Declares a query parameter with default value", param.Default("Carmack")),
		option.Header("Authorization", "Bearer token", param.Required()),
		optionPagination,
		optionCustomBehavior,
	)

	s.Run()
}

var optionPagination = option.Group(
	option.QueryInt("page", "Page number", param.Default(1), param.Example("1st page", 1), param.Example("42nd page", 42)),
	option.QueryInt("perPage", "Number of items per page"),
)

var optionCustomBehavior = func(r *fuego.BaseRoute) {
	r.XXX = "YYY"
}
Std lib compatibility
package main

import (
	"net/http"

	"github.com/go-fuego/fuego"
)

func main() {
	s := fuego.NewServer()

	// Standard net/http middleware
	fuego.Use(s, func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("X-Hello", "World")
			next.ServeHTTP(w, r)
		})
	})

	// Standard net/http handler with automatic OpenAPI route declaration
	fuego.GetStd(s, "/std", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	})

	s.Run()
}
Real-world examples

Please see the /examples folder for more examples.

All features
package main

import (
	"context"
	"errors"
	"net/http"
	"strings"

	chiMiddleware "github.com/go-chi/chi/v5/middleware"
	"github.com/rs/cors"

	"github.com/go-fuego/fuego"
)

type Received struct {
	Name string `json:"name" validate:"required"`
}

type MyResponse struct {
	Message       string `json:"message"`
	BestFramework string `json:"best"`
}

func main() {
	s := fuego.NewServer(
		fuego.WithAddr("localhost:8088"),
	)

	fuego.Use(s, cors.Default().Handler)
	fuego.Use(s, chiMiddleware.Compress(5, "text/html", "text/css"))

	// Fuego 🔥 handler with automatic OpenAPI generation, validation, (de)serialization and error handling
	fuego.Post(s, "/", func(c *fuego.ContextWithBody[Received]) (MyResponse, error) {
		data, err := c.Body()
		if err != nil {
			return MyResponse{}, err
		}

		c.Response().Header().Set("X-Hello", "World")

		return MyResponse{
			Message:       "Hello, " + data.Name,
			BestFramework: "Fuego!",
		}, nil
	})

	// Standard net/http handler with automatic OpenAPI route declaration
	fuego.GetStd(s, "/std", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	})

	s.Run()
}

// InTransform will be called when using c.Body().
// It can be used to transform the entity and raise custom errors
func (r *Received) InTransform(context.Context) error {
	r.Name = strings.ToLower(r.Name)
	if r.Name == "fuego" {
		return errors.New("fuego is not a name")
	}
	return nil
}

// OutTransform will be called before sending data
func (r *MyResponse) OutTransform(context.Context) error {
	r.Message = strings.ToUpper(r.Message)
	return nil
}
curl  http://localhost:8088/std
# Hello, World!
curl http://localhost:8088 -X POST -d '{"name": "Your Name"}' -H 'Content-Type: application/json'
# {"message":"HELLO, YOUR NAME","best":"Fuego!"}
curl http://localhost:8088 -X POST -d '{"name": "Fuego"}' -H 'Content-Type: application/json'
# {"error":"cannot transform request body: cannot transform request body: fuego is not a name"}

From net/http to Fuego in 10s

https://github.com/go-fuego/fuego/assets/46993939/7438a71c-75a4-4e88-a584-71da6362c575

Views
Before
image
After
image
Diff
image
Benefits of using Fuego views (controllers returning HTML)
  • Never forget to return after an error
  • OpenAPI schema generated, listing all the routes
  • Deserialization and validation are easier
  • Transition to Fuego is easy and fast

Contributing

See the contributing guide. Thanks to everyone who has contributed to this project! ❤️

Graph of contributors

Made with contrib.rocks

Roadmap

See the board.

Disclaimer for experienced gophers

I know you might prefer to use net/http directly, but if having a frame can convince my company to use Go instead of Node, I'm happy to use it.

License

MIT

Documentation

Index

Examples

Constants

View Source
const JWTCookieName = "jwt_token"

Variables

View Source
var (
	ErrUnauthorized     = errors.New("unauthorized")
	ErrTokenNotFound    = errors.New("token not found")
	ErrInvalidTokenType = errors.New("invalid token type")
	ErrInvalidRolesType = errors.New("invalid role type. Must be []string")
	ErrExpired          = errors.New("token is expired")
)
View Source
var ReadOptions = readOptions{
	DisallowUnknownFields: true,
	MaxBodySize:           maxBodySize,
}
View Source
var SendError = func(w http.ResponseWriter, r *http.Request, err error) {
	for _, header := range parseAcceptHeader(r.Header) {
		switch inferAcceptHeader(header, nil) {
		case "application/xml":
			SendXMLError(w, nil, err)
		case "text/html":
			SendHTMLError(w, nil, err)
		case "text/plain":
			SendTextError(w, r, err)
		case "application/json":
			SendJSONError(w, nil, err)
		case "application/x-yaml", "text/yaml; charset=utf-8", "application/yaml":
			SendYAMLError(w, nil, err)
		default:
			continue
		}
		return
	}
	SendJSONError(w, r, err)
}

SendError sends an error. Declared as a variable to be able to override it for clients that need to customize serialization.

View Source
var SendHTML = func(w http.ResponseWriter, r *http.Request, ans any) error {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")

	ctxRenderer, ok := any(ans).(CtxRenderer)
	if ok {
		return ctxRenderer.Render(r.Context(), w)
	}

	renderer, ok := any(ans).(Renderer)
	if ok {
		return renderer.Render(w)
	}

	html, ok := any(ans).(HTML)
	if ok {
		_, err := w.Write([]byte(html))
		return err
	}

	htmlString, ok := any(ans).(string)
	if ok {
		_, err := w.Write([]byte(htmlString))
		return err
	}

	return fmt.Errorf("cannot serialize HTML from type %T (not string, fuego.HTML and does not implement fuego.CtxRenderer or fuego.Renderer)", ans)
}

SendHTML sends a HTML response. Declared as a variable to be able to override it for clients that need to customize serialization.

View Source
var SendJSON = func(w http.ResponseWriter, _ *http.Request, ans any) error {
	w.Header().Set("Content-Type", "application/json")
	err := json.NewEncoder(w).Encode(ans)
	if err != nil {
		slog.Error("Cannot serialize returned response to JSON", "error", err, "errtype", fmt.Sprintf("%T", err))
		var unsupportedType *json.UnsupportedTypeError
		if errors.As(err, &unsupportedType) {
			return NotAcceptableError{
				Err:    err,
				Detail: fmt.Sprintf("Cannot serialize type %T to JSON", ans),
			}
		}
	}
	return err
}

SendJSON sends a JSON response. Declared as a variable to be able to override it for clients that need to customize serialization. If serialization fails, it does NOT write to the response writer. It has to be passed to SendJSONError.

View Source
var SendXML = func(w http.ResponseWriter, _ *http.Request, ans any) error {
	w.Header().Set("Content-Type", "application/xml")
	err := xml.NewEncoder(w).Encode(ans)
	if err != nil {
		slog.Error("Cannot serialize returned response to XML", "error", err, "errtype", fmt.Sprintf("%T", err))
		var unsupportedType *xml.UnsupportedTypeError
		if errors.As(err, &unsupportedType) {
			return NotAcceptableError{
				Err:    err,
				Detail: fmt.Sprintf("Cannot serialize type %T to XML", ans),
			}
		}
	}

	return err
}

SendXML sends a XML response. Declared as a variable to be able to override it for clients that need to customize serialization. If serialization fails, it does NOT write to the response writer. It has to be passed to SendJSONError.

View Source
var SendYAML = func(w http.ResponseWriter, _ *http.Request, ans any) (err error) {

	defer func() {
		if r := recover(); r != nil {
			err = HTTPError{
				Err:    fmt.Errorf("cannot serialize to YAML: %v", r),
				Detail: "Cannot serialize returned response to YAML",
			}
		}
	}()

	w.Header().Set("Content-Type", "application/x-yaml")
	err = yaml.NewEncoder(w).Encode(ans)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		slog.Error("Cannot serialize returned response to YAML", "error", err)
		_, _ = w.Write([]byte(`{"error":"Cannot serialize returned response to YAML"}`))
	}
	return err
}

SendYAML sends a YAML response. Declared as a variable to be able to override it for clients that need to customize serialization. If serialization fails, it does NOT write to the response writer. It has to be passed to SendJSONError.

Functions

func AuthWall

func AuthWall(authorizedRoles ...string) func(next http.Handler) http.Handler

AuthWall is a middleware that checks if the user is authorized. If not, it returns an error. If authorized roles are provided, the user must have at least one of its role in the list. For example:

AuthWall("admin", "chef") // Will block a user with the "waiter" role and allow a user with a role "chef".
AuthWall("chef") // Will block a user with the "admin" and "client" role.
AuthWall() // Will block all users. To simply Check if the user is authenticated, use the [TokenToContext] middleware.

See the tests for more examples.

func AuthWallRegex

func AuthWallRegex(acceptedRolesRegex string) func(next http.Handler) http.Handler

AuthWallRegex is a middleware that checks if the user is authorized. If not, it returns an error. If authorized roles are provided, the user must have at least one of its role in the list that matches the regex. For example:

AuthWallRegex(`^(super)?admin$`) // Will block a user with the "waiter" role and allow a user with a role "admin".

See the tests for more examples.

func AuthWallRegexp

func AuthWallRegexp(acceptedRolesRegex *regexp.Regexp) func(next http.Handler) http.Handler

AuthWallRegexp is a middleware that checks if the user is authorized. If not, it returns an error. If authorized roles are provided, the user must have at least one of its role in the list that matches the regex. For example:

myRegexRule := regexp.MustCompile(`^(super)?admin$`)
AuthWallRegex(myRegexRule) // Will block a user with the "waiter" role and allow a user with a role "admin".

See the tests for more examples.

func DefaultOpenAPIHandler

func DefaultOpenAPIHandler(specURL string) http.Handler

func ErrorHandler

func ErrorHandler(err error) error

ErrorHandler is the default error handler used by the framework. It transforms any error into the unified error type HTTPError, Using the ErrorWithStatus interface.

func FuncName

func FuncName(f interface{}) string

FuncName returns the name of a function and the name with package path

func GetToken

func GetToken[T any](ctx context.Context) (T, error)

GetToken returns the validated token from the context, if found. To check if the user is authorized, use the AuthWall middleware, or create your own middleware. Example:

token, err := fuego.GetToken[MyCustomTokenType](ctx.Context())

func GroupOptions

func GroupOptions(options ...func(*BaseRoute)) func(*BaseRoute)

Group allows to group routes under a common path. Useful to group often used middlewares or options and reuse them. Example:

optionsPagination := option.Group(
	option.QueryInt("per_page", "Number of items per page", ParamRequired()),
	option.QueryInt("page", "Page number", ParamDefault(1)),
)

func HTTPHandler

func HTTPHandler[ReturnType, Body any, Contextable ctx[Body]](s *Server, controller func(c Contextable) (ReturnType, error), route *BaseRoute) http.HandlerFunc

HTTPHandler converts a Fuego controller into a http.HandlerFunc. Uses Server for configuration. Uses Route for route configuration. Optional.

func InferAcceptHeaderFromType

func InferAcceptHeaderFromType(ans any) string

func NewOpenApiSpec

func NewOpenApiSpec() openapi3.T

func OptionAddError

func OptionAddError(code int, description string, errorType ...any) func(*BaseRoute)

AddError adds an error to the route. Required: should only supply one type to `errorType`

func OptionCookie

func OptionCookie(name, description string, options ...func(*OpenAPIParam)) func(*BaseRoute)

Declare a cookie parameter for the route. This will be added to the OpenAPI spec. Example:

Cookie("session_id", "Session ID", ParamRequired())

The list of options is in the param package.

func OptionDeprecated

func OptionDeprecated() func(*BaseRoute)

Deprecated marks the route as deprecated.

func OptionDescription

func OptionDescription(description string) func(*BaseRoute)

Description adds a description to the route.

func OptionHeader

func OptionHeader(name, description string, options ...func(*OpenAPIParam)) func(*BaseRoute)

Declare a header parameter for the route. This will be added to the OpenAPI spec. Example:

Header("Authorization", "Bearer token", ParamRequired())

The list of options is in the param package.

func OptionHide

func OptionHide() func(*BaseRoute)

Hide hides the route from the OpenAPI spec.

func OptionMiddleware

func OptionMiddleware(middleware ...func(http.Handler) http.Handler) func(*BaseRoute)

Middleware adds one or more route-scoped middleware.

func OptionOperationID

func OptionOperationID(operationID string) func(*BaseRoute)

OperationID adds an operation ID to the route.

func OptionParam

func OptionParam(name string, options ...func(*OpenAPIParam)) func(*BaseRoute)

Registers a parameter for the route. Prefer using the [Query], [QueryInt], [Header], [Cookie] shortcuts.

func OptionQuery

func OptionQuery(name, description string, options ...func(*OpenAPIParam)) func(*BaseRoute)

Declare a query parameter for the route. This will be added to the OpenAPI spec. Example:

Query("name", "Filter by name", ParamExample("cat name", "felix"), ParamNullable())

The list of options is in the param package.

func OptionQueryBool

func OptionQueryBool(name, description string, options ...func(*OpenAPIParam)) func(*BaseRoute)

Declare a boolean query parameter for the route. This will be added to the OpenAPI spec. The query parameter is transmitted as a string in the URL, but it is parsed as a boolean. Example:

QueryBool("is_active", "Filter by active status", ParamExample("true", true), ParamNullable())

The list of options is in the param package.

func OptionQueryInt

func OptionQueryInt(name, description string, options ...func(*OpenAPIParam)) func(*BaseRoute)

Declare an integer query parameter for the route. This will be added to the OpenAPI spec. The query parameter is transmitted as a string in the URL, but it is parsed as an integer. Example:

QueryInt("age", "Filter by age (in years)", ParamExample("3 years old", 3), ParamNullable())

The list of options is in the param package.

func OptionRequestContentType

func OptionRequestContentType(consumes ...string) func(*BaseRoute)

RequestContentType sets the accepted content types for the route. By default, the accepted content types is */*. This will override any options set at the server level.

func OptionSummary

func OptionSummary(summary string) func(*BaseRoute)

Summary adds a summary to the route.

func OptionTags

func OptionTags(tags ...string) func(*BaseRoute)

Tags adds one or more tags to the route.

func ParamBool

func ParamBool() func(param *OpenAPIParam)

func ParamDefault

func ParamDefault(value any) func(param *OpenAPIParam)

func ParamDescription

func ParamDescription(description string) func(param *OpenAPIParam)

func ParamExample

func ParamExample(exampleName string, value any) func(param *OpenAPIParam)

Example adds an example to the parameter. As per the OpenAPI 3.0 standard, the example must be given a name.

func ParamInteger

func ParamInteger() func(param *OpenAPIParam)

func ParamNullable

func ParamNullable() func(param *OpenAPIParam)

func ParamRequired

func ParamRequired() func(param *OpenAPIParam)

func ParamString

func ParamString() func(param *OpenAPIParam)

func ReadJSON

func ReadJSON[B any](context context.Context, input io.Reader) (B, error)

ReadJSON reads the request body as JSON. Can be used independently of Fuego framework. Customizable by modifying ReadOptions.

func ReadString

func ReadString[B ~string](context context.Context, input io.Reader) (B, error)

ReadString reads the request body as string. Can be used independently of Fuego framework. Customizable by modifying ReadOptions.

func ReadURLEncoded

func ReadURLEncoded[B any](r *http.Request) (B, error)

ReadURLEncoded reads the request body as HTML Form.

func ReadXML

func ReadXML[B any](context context.Context, input io.Reader) (B, error)

ReadXML reads the request body as XML. Can be used independently of Fuego framework. Customizable by modifying ReadOptions.

func ReadYAML

func ReadYAML[B any](context context.Context, input io.Reader) (B, error)

ReadYAML reads the request body as YAML. Can be used independently of Fuego framework. Customizable by modifying ReadOptions.

func RegisterOpenAPIOperation

func RegisterOpenAPIOperation[T, B any](s *Server, route Route[T, B]) (*openapi3.Operation, error)

RegisterOpenAPIOperation registers an OpenAPI operation.

func Send

func Send(w http.ResponseWriter, r *http.Request, ans any) (err error)

Send sends a response. The format is determined by the Accept header. If Accept header `*/*` is found Send will Attempt to send HTML, and then JSON.

func SendHTMLError

func SendHTMLError(w http.ResponseWriter, _ *http.Request, err error)

SendHTMLError sends a HTML response. If the error implements ErrorWithStatus, the status code will be set.

func SendJSONError

func SendJSONError(w http.ResponseWriter, _ *http.Request, err error)

SendJSONError sends a JSON error response. If the error implements ErrorWithStatus, the status code will be set.

func SendText

func SendText(w http.ResponseWriter, _ *http.Request, ans any) error

SendText sends a HTML response. Declared as a variable to be able to override it for clients that need to customize serialization.

func SendTextError

func SendTextError(w http.ResponseWriter, _ *http.Request, err error)

SendTextError sends a Text response. If the error implements ErrorWithStatus, the status code will be set.

func SendXMLError

func SendXMLError(w http.ResponseWriter, _ *http.Request, err error)

SendXMLError sends a XML error response. If the error implements ErrorWithStatus, the status code will be set.

func SendYAMLError

func SendYAMLError(w http.ResponseWriter, _ *http.Request, err error)

SendYAMLError sends a YAML error response. If the error implements ErrorWithStatus, the status code will be set.

func TokenFromContext

func TokenFromContext(ctx context.Context) (jwt.Claims, error)

TokenFromContext returns the validated token from the context, if found. To check if the user is authorized, use the AuthWall middleware, or create your own middleware. Even though it returns a jwt.MapClaims, the real underlying type is the one you chose when calling Security.GenerateToken. Example:

token, err := fuego.TokenFromContext[MyCustomTokenType](ctx.Context())

func TokenFromCookie

func TokenFromCookie(r *http.Request) string

func TokenFromHeader

func TokenFromHeader(r *http.Request) string

func TokenFromQueryParam

func TokenFromQueryParam(r *http.Request) string

func Use

func Use(s *Server, middlewares ...func(http.Handler) http.Handler)

func UseStd

func UseStd(s *Server, middlewares ...func(http.Handler) http.Handler)

func WithAddr

func WithAddr(addr string) func(*Server)

WithAddr optionally specifies the TCP address for the server to listen on, in the form "host:port". If not specified addr ':9999' will be used.

func WithAutoAuth

func WithAutoAuth(verifyUserInfo func(user, password string) (jwt.Claims, error)) func(*Server)

func WithBasePath

func WithBasePath(basePath string) func(*Server)

func WithCorsMiddleware

func WithCorsMiddleware(corsMiddleware func(http.Handler) http.Handler) func(*Server)

WithCorsMiddleware registers a middleware to handle CORS. It is not handled like other middlewares with Use because it applies routes that are not registered. For example:

import "github.com/rs/cors"

s := fuego.NewServer(
	WithCorsMiddleware(cors.New(cors.Options{
		AllowedOrigins:   []string{"*"},
		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowedHeaders:   []string{"*"},
		AllowCredentials: true,
	}).Handler)
)

func WithDisallowUnknownFields

func WithDisallowUnknownFields(b bool) func(*Server)

WithDisallowUnknownFields sets the DisallowUnknownFields option. If true, the server will return an error if the request body contains unknown fields. Useful for quick debugging in development. Defaults to true.

func WithErrorHandler

func WithErrorHandler(errorHandler func(err error) error) func(*Server)

func WithErrorSerializer

func WithErrorSerializer(serializer ErrorSender) func(*Server)

WithErrorSerializer sets a custom serializer of type ErrorSender that overrides the default one. Please send a PR if you think the default serializer should be improved, instead of jumping to this option.

func WithGlobalResponseTypes

func WithGlobalResponseTypes(code int, description string, errorType ...any) func(*Server)

WithGlobalResponseTypes adds default response types to the server. useful for adding global error types. For example:

app := fuego.NewServer(
	fuego.WithGlobalResponseTypes(400, "Bad Request _(validation or deserialization error)_", HTTPError{}),
	fuego.WithGlobalResponseTypes(401, "Unauthorized _(authentication error)_", HTTPError{}),
	fuego.WithGlobalResponseTypes(500, "Internal Server Error _(panics)_", HTTPError{}),
)

func WithLogHandler

func WithLogHandler(handler slog.Handler) func(*Server)

WithLogHandler sets the log handler of the server.

func WithMaxBodySize

func WithMaxBodySize(maxBodySize int64) func(*Server)

func WithOpenAPIConfig

func WithOpenAPIConfig(openapiConfig OpenAPIConfig) func(*Server)

func WithPort deprecated

func WithPort(port int) func(*Server)

WithPort sets the port of the server. For example, 8080. If not specified, the default port is 9999. If you want to use a different address, use WithAddr instead.

Deprecated: Please use fuego.WithAddr(addr string)

func WithRequestContentType

func WithRequestContentType(consumes ...string) func(*Server)

WithRequestContentType sets the accepted content types for the server. By default, the accepted content types is */*.

func WithRouteOptions

func WithRouteOptions(options ...func(*BaseRoute)) func(*Server)

func WithSerializer

func WithSerializer(serializer Sender) func(*Server)

WithSerializer sets a custom serializer of type Sender that overrides the default one. Please send a PR if you think the default serializer should be improved, instead of jumping to this option.

func WithTemplateFS

func WithTemplateFS(fs fs.FS) func(*Server)

WithTemplateFS sets the filesystem used to load templates. To be used with WithTemplateGlobs or WithTemplates. For example:

WithTemplateFS(os.DirFS("./templates"))

or with embedded templates:

//go:embed templates
var templates embed.FS
...
WithTemplateFS(templates)

func WithTemplateGlobs

func WithTemplateGlobs(patterns ...string) func(*Server)

WithTemplateGlobs loads templates matching the given patterns from the server filesystem. If the server filesystem is not set, it will use the OS filesystem, at folder "./templates". For example:

WithTemplateGlobs("*.html, */*.html", "*/*/*.html")
WithTemplateGlobs("pages/*.html", "pages/admin/*.html")

for reference about the glob patterns in Go (no ** support for example): https://pkg.go.dev/path/filepath?utm_source=godoc#Match

func WithTemplates

func WithTemplates(templates *template.Template) func(*Server)

WithTemplates loads the templates used to render HTML. To be used with WithTemplateFS. If not set, it will use the os filesystem, at folder "./templates".

func WithValidator

func WithValidator(newValidator *validator.Validate) func(*Server)

WithValidator sets the validator to be used by the fuego server. If no validator is provided, a default validator will be used.

Note: If you are using the default validator, you can add tags to your structs using the `validate` tag. For example:

type MyStruct struct {
	Field1 string `validate:"required"`
	Field2 int    `validate:"min=10,max=20"`
}

The above struct will be validated using the default validator, and if any errors occur, they will be returned as part of the response.

func WithValue

func WithValue(ctx context.Context, val any) context.Context

func WithXML deprecated

func WithXML() func(*Server)

WithXML sets the serializer to XML

Deprecated: fuego supports automatic XML serialization when using the header "Accept: application/xml".

func WithoutAutoGroupTags

func WithoutAutoGroupTags() func(*Server)

WithoutAutoGroupTags disables the automatic grouping of routes by tags. By default, routes are tagged by group. For example:

recipeGroup := fuego.Group(s, "/recipes")
fuego.Get(recipeGroup, "/", func(*ContextNoBody) (ans, error) {
	return ans{}, nil
})

RecipeThis route will be tagged with "recipes" by default, but with this option, they will not be tagged.

func WithoutLogger

func WithoutLogger() func(*Server)

WithoutLogger disables the default logger.

func WithoutStartupMessages

func WithoutStartupMessages() func(*Server)

WithoutStartupMessages disables the startup message

Types

type AutoAuthConfig

type AutoAuthConfig struct {
	Enabled        bool
	VerifyUserInfo func(user, password string) (jwt.Claims, error) // Must check the username and password, and return the claims
}

type BadRequestError

type BadRequestError HTTPError

BadRequestError is an error used to return a 400 status code.

func (BadRequestError) Error

func (e BadRequestError) Error() string

func (BadRequestError) StatusCode

func (e BadRequestError) StatusCode() int

func (BadRequestError) Unwrap

func (e BadRequestError) Unwrap() error

type BaseRoute

type BaseRoute struct {
	Operation            *openapi3.Operation // GENERATED OpenAPI operation, do not set manually in Register function. You can change it after the route is registered.
	Method               string              // HTTP method (GET, POST, PUT, PATCH, DELETE)
	Path                 string              // URL path. Will be prefixed by the base path of the server and the group path if any
	Handler              http.Handler        // handler executed for this route
	FullName             string              // namespace and name of the function to execute
	Params               map[string]OpenAPIParam
	Middlewares          []func(http.Handler) http.Handler
	AcceptedContentTypes []string // Content types accepted for the request body. If nil, all content types (*/*) are accepted.
	Hidden               bool     // If true, the route will not be documented in the OpenAPI spec
	// contains filtered or unexported fields
}

type ConflictError

type ConflictError HTTPError

ConflictError is an error used to return a 409 status code.

func (ConflictError) Error

func (e ConflictError) Error() string

func (ConflictError) StatusCode

func (e ConflictError) StatusCode() int

func (ConflictError) Unwrap

func (e ConflictError) Unwrap() error

type ContextNoBody

type ContextNoBody struct {
	Req *http.Request
	Res http.ResponseWriter
	// contains filtered or unexported fields
}

ContextNoBody is used when the controller does not have a body. It is used as a base context for other Context types.

func (ContextNoBody) Body

func (c ContextNoBody) Body() (any, error)

func (ContextNoBody) Context

func (c ContextNoBody) Context() context.Context

ContextNoBody implements the context interface via net/http.Request.Context

func (ContextNoBody) Cookie

func (c ContextNoBody) Cookie(name string) (*http.Cookie, error)

Get request cookie

func (ContextNoBody) Deadline

func (c ContextNoBody) Deadline() (deadline time.Time, ok bool)

ContextNoBody implements the context interface via net/http.Request.Context

func (ContextNoBody) Done

func (c ContextNoBody) Done() <-chan struct{}

ContextNoBody implements the context interface via net/http.Request.Context

func (ContextNoBody) Err

func (c ContextNoBody) Err() error

ContextNoBody implements the context interface via net/http.Request.Context

func (ContextNoBody) HasCookie

func (c ContextNoBody) HasCookie(name string) bool

Has request cookie

func (ContextNoBody) HasHeader

func (c ContextNoBody) HasHeader(key string) bool

Has request header

func (ContextNoBody) Header

func (c ContextNoBody) Header(key string) string

Get request header

func (ContextNoBody) MainLang

func (c ContextNoBody) MainLang() string

func (ContextNoBody) MainLocale

func (c ContextNoBody) MainLocale() string

func (ContextNoBody) MustBody

func (c ContextNoBody) MustBody() any

func (ContextNoBody) PathParam

func (c ContextNoBody) PathParam(name string) string

PathParams returns the path parameters of the request.

func (ContextNoBody) QueryParam

func (c ContextNoBody) QueryParam(name string) string

QueryParam returns the query parameter with the given name. If it does not exist, it returns an empty string, unless there is a default value declared in the OpenAPI spec.

Example:

fuego.Get(s, "/test", myController,
  option.Query("name", "Name", param.Default("hey"))
)

func (ContextNoBody) QueryParamArr

func (c ContextNoBody) QueryParamArr(name string) []string

QueryParamsArr returns an slice of string from the given query parameter.

func (ContextNoBody) QueryParamBool

func (c ContextNoBody) QueryParamBool(name string) bool

QueryParamBool returns the query parameter with the given name as a bool. If the query parameter does not exist or is not a bool, it returns false. Accepted values are defined as strconv.ParseBool Example:

fuego.Get(s, "/test", myController,
  option.QueryBool("is_ok", "Is OK?", param.Default(true))
)

and the query parameter does not exist in the HTTP request, it will return true.

func (ContextNoBody) QueryParamBoolErr

func (c ContextNoBody) QueryParamBoolErr(name string) (bool, error)

QueryParamBool returns the query parameter with the given name as a bool. If the query parameter does not exist or is not a bool, it returns the default value declared in the OpenAPI spec. For example, if the query parameter is declared as:

fuego.Get(s, "/test", myController,
  option.QueryBool("is_ok", "Is OK?", param.Default(true))
)

and the query parameter does not exist in the HTTP request, it will return true. Accepted values are defined as strconv.ParseBool

func (ContextNoBody) QueryParamInt

func (c ContextNoBody) QueryParamInt(name string) int

QueryParamInt returns the query parameter with the given name as an int. If it does not exist, it returns the default value declared in the OpenAPI spec. For example, if the query parameter is declared as:

fuego.Get(s, "/test", myController,
  option.QueryInt("page", "Page number", param.Default(1))
)

and the query parameter does not exist, it will return 1. If the query parameter does not exist and there is no default value, or if it is not an int, it returns 0.

func (ContextNoBody) QueryParamIntErr

func (c ContextNoBody) QueryParamIntErr(name string) (int, error)

func (ContextNoBody) QueryParams

func (c ContextNoBody) QueryParams() url.Values

QueryParams returns the query parameters of the request. It is a shortcut for c.Req.URL.Query().

func (ContextNoBody) Redirect

func (c ContextNoBody) Redirect(code int, url string) (any, error)

func (ContextNoBody) Render

func (c ContextNoBody) Render(templateToExecute string, data any, layoutsGlobs ...string) (CtxRenderer, error)

Render renders the given templates with the given data. It returns just an empty string, because the response is written directly to the http.ResponseWriter.

Init templates if not already done. This has the side effect of making the Render method static, meaning that the templates will be parsed only once, removing the need to parse the templates on each request but also preventing to dynamically use new templates.

func (ContextNoBody) Request

func (c ContextNoBody) Request() *http.Request

Request returns the HTTP request.

func (ContextNoBody) Response

func (c ContextNoBody) Response() http.ResponseWriter

Response returns the HTTP response writer.

func (ContextNoBody) SetCookie

func (c ContextNoBody) SetCookie(cookie http.Cookie)

Sets response cookie

Example
s := NewServer()
Get(s, "/test", func(c *ContextNoBody) (string, error) {
	c.SetCookie(http.Cookie{
		Name:  "name",
		Value: "value",
	})
	return "test", nil
})

w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/test", nil)

s.Mux.ServeHTTP(w, r)

fmt.Println(w.Result().Cookies()[0].Name)
fmt.Println(w.Result().Cookies()[0].Value)
Output:

name
value

func (ContextNoBody) SetHeader

func (c ContextNoBody) SetHeader(key, value string)

Sets response header

Example
s := NewServer()
Get(s, "/test", func(c *ContextNoBody) (string, error) {
	c.SetHeader("X-Test", "test")
	return "test", nil
})

w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/test", nil)

s.Mux.ServeHTTP(w, r)

fmt.Println(w.Header().Get("X-Test"))
Output:

test

func (ContextNoBody) SetStatus

func (c ContextNoBody) SetStatus(code int)

SetStatus sets the status code of the response. Alias to http.ResponseWriter.WriteHeader.

func (ContextNoBody) Value

func (c ContextNoBody) Value(key any) any

ContextNoBody implements the context interface via net/http.Request.Context

type ContextWithBody

type ContextWithBody[Body any] struct {
	ContextNoBody
	// contains filtered or unexported fields
}

ContextWithBody is the same as fuego.ContextNoBody, but has a Body. The Body type parameter represents the expected data type from http.Request.Body. Please do not use a pointer as a type parameter.

func NewContext

func NewContext[B any](w http.ResponseWriter, r *http.Request, options readOptions) *ContextWithBody[B]

NewContext returns a new context. It is used internally by Fuego. You probably want to use Ctx[B] instead.

func (*ContextWithBody[B]) Body

func (c *ContextWithBody[B]) Body() (B, error)

Body returns the body of the request. If (*B) implements InTransformer, it will be transformed after deserialization. It caches the result, so it can be called multiple times. The reason the body is cached is that it is impossible to read an HTTP request body multiple times, not because of performance. For decoding, it uses the Content-Type header. If it is not set, defaults to application/json.

func (*ContextWithBody[B]) MustBody

func (c *ContextWithBody[B]) MustBody() B

MustBody works like Body, but panics if there is an error.

type CtxRenderer

type CtxRenderer interface {
	Render(context.Context, io.Writer) error
}

CtxRenderer is an interface that can be used to render a response. It is used with standard library templating engine, by using fuego.ContextXXX.Render It is compatible with github.com/a-h/templ out of the box. Example:

func getRecipes(ctx fuego.ContextNoBody) (fuego.CtxRenderer, error) {
	recipes, err := ctx.store.GetRecipes(ctx.Context())
	if err != nil {
		return nil, err
	}

	return recipeComponent(recipes), nil // recipeComponent is templ component
}

type DataOrTemplate

type DataOrTemplate[T any] struct {
	Data     T
	Template any
}

DataOrTemplate is a struct that can return either data or a template depending on the asked type.

func DataOrHTML

func DataOrHTML[T any](data T, template any) *DataOrTemplate[T]

Helper function to create a DataOrTemplate return item without specifying the type.

func (DataOrTemplate[T]) MarshalJSON

func (m DataOrTemplate[T]) MarshalJSON() ([]byte, error)

func (DataOrTemplate[T]) MarshalXML

func (m DataOrTemplate[T]) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

func (DataOrTemplate[T]) MarshalYAML

func (m DataOrTemplate[T]) MarshalYAML() (interface{}, error)

func (DataOrTemplate[T]) Render

func (m DataOrTemplate[T]) Render(c context.Context, w io.Writer) error

func (DataOrTemplate[T]) String

func (m DataOrTemplate[T]) String() string

type ErrorItem

type ErrorItem struct {
	Name   string         `json:"name" xml:"name" description:"For example, name of the parameter that caused the error"`
	Reason string         `json:"reason" xml:"reason" description:"Human readable error message"`
	More   map[string]any `json:"more,omitempty" xml:"more,omitempty" description:"Additional information about the error"`
}

type ErrorSender

type ErrorSender = func(http.ResponseWriter, *http.Request, error)

type ErrorWithStatus

type ErrorWithStatus interface {
	error
	StatusCode() int
}

ErrorWithStatus is an interface that can be implemented by an error to provide additional information about the error.

type ForbiddenError

type ForbiddenError HTTPError

ForbiddenError is an error used to return a 403 status code.

func (ForbiddenError) Error

func (e ForbiddenError) Error() string

func (ForbiddenError) StatusCode

func (e ForbiddenError) StatusCode() int

func (ForbiddenError) Unwrap

func (e ForbiddenError) Unwrap() error

type Gomponent

type Gomponent = Renderer

Gomponent is a shortcut for Renderer, which can be used with github.com/maragudk/gomponents

type H

type H map[string]any

H is a shortcut for map[string]any

type HTML

type HTML string

HTML is a marker type used to differentiate between a string response and an HTML response. To use templating, use [Ctx.Render].

type HTTPError

type HTTPError struct {
	Err  error  `json:"-" xml:"-"` // Developer readable error message. Not shown to the user to avoid security leaks.
	Type string ``                 // URL of the error type. Can be used to lookup the error in a documentation
	/* 130-byte string literal not displayed */
	Title    string      `json:"title,omitempty" xml:"title,omitempty" description:"Short title of the error"`         // Short title of the error
	Status   int         `json:"status,omitempty" xml:"status,omitempty" description:"HTTP status code" example:"403"` // HTTP status code. If using a different type than [HTTPError], for example [BadRequestError], this will be automatically overridden after Fuego error handling.
	Detail   string      `json:"detail,omitempty" xml:"detail,omitempty" description:"Human readable error message"`   // Human readable error message
	Instance string      `json:"instance,omitempty" xml:"instance,omitempty"`
	Errors   []ErrorItem `json:"errors,omitempty" xml:"errors,omitempty"`
}

HTTPError is the error response used by the serialization part of the framework.

func (HTTPError) Error

func (e HTTPError) Error() string

func (HTTPError) StatusCode

func (e HTTPError) StatusCode() int

func (HTTPError) Unwrap

func (e HTTPError) Unwrap() error

type InTransformer

type InTransformer interface {
	InTransform(context.Context) error // InTransforms the entity.
}

InTransformer is an interface for entities that can be transformed. Useful for example for trimming strings, changing case, etc. Can also raise an error if the entity is not valid.

type InternalServerError

type InternalServerError = HTTPError

InternalServerError is an error used to return a 500 status code.

type LoginPayload

type LoginPayload struct {
	User     string `json:"user" validate:"required"` // Might be an email, a username, or anything else that identifies uniquely the user
	Password string `json:"password" validate:"required"`
}

type NotAcceptableError

type NotAcceptableError HTTPError

NotAcceptableError is an error used to return a 406 status code.

func (NotAcceptableError) Error

func (e NotAcceptableError) Error() string

func (NotAcceptableError) StatusCode

func (e NotAcceptableError) StatusCode() int

func (NotAcceptableError) Unwrap

func (e NotAcceptableError) Unwrap() error

type NotFoundError

type NotFoundError HTTPError

NotFoundError is an error used to return a 404 status code.

func (NotFoundError) Error

func (e NotFoundError) Error() string

func (NotFoundError) StatusCode

func (e NotFoundError) StatusCode() int

func (NotFoundError) Unwrap

func (e NotFoundError) Unwrap() error

type OpenAPIConfig

type OpenAPIConfig struct {
	DisableSwagger   bool                              // If true, the server will not serve the Swagger UI nor the OpenAPI JSON spec
	DisableSwaggerUI bool                              // If true, the server will not serve the Swagger UI
	DisableLocalSave bool                              // If true, the server will not save the OpenAPI JSON spec locally
	SwaggerUrl       string                            // URL to serve the swagger UI
	UIHandler        func(specURL string) http.Handler // Handler to serve the OpenAPI UI from spec URL
	JsonUrl          string                            // URL to serve the OpenAPI JSON spec
	JsonFilePath     string                            // Local path to save the OpenAPI JSON spec
	PrettyFormatJson bool                              // Pretty prints the OpenAPI spec with proper JSON indentation
}

type OpenAPIDescriptioner

type OpenAPIDescriptioner interface {
	Description() string
}

type OpenAPIParam

type OpenAPIParam struct {
	Name        string
	Description string
	OpenAPIParamOption
}

type OpenAPIParamOption

type OpenAPIParamOption struct {
	Required bool
	Nullable bool
	Default  any // Default value for the parameter
	Example  string
	Examples map[string]any
	Type     ParamType
	GoType   string // integer, string, bool
}

type OutTransformer

type OutTransformer interface {
	OutTransform(context.Context) error // Transforms an entity before sending it.
}

OutTransformer is an interface for entities that can be transformed. Useful for example for trimming strings, changing case, etc. Can also raise an error if the entity is not valid. Must be implemented by a POINTER RECEIVER. Example:

type User struct {
	Name     string `json:"name"`
	Password string `json:"password"`
}

// Not (u User) but (u *User)

func (u *User) OutTransform(context.Context) error {
	u.Name = "M. " + u.Name
	u.Password = "*****"
	return nil
}

type ParamType

type ParamType string // Query, Header, Cookie
const (
	QueryParamType  ParamType = "query"
	HeaderParamType ParamType = "header"
	CookieParamType ParamType = "cookie"
)

type QueryParamInvalidTypeError

type QueryParamInvalidTypeError struct {
	ParamName    string
	ParamValue   string
	ExpectedType string
	Err          error
}

func (QueryParamInvalidTypeError) Error

type QueryParamNotFoundError

type QueryParamNotFoundError struct {
	ParamName string
}

func (QueryParamNotFoundError) Error

func (e QueryParamNotFoundError) Error() string

type Renderer

type Renderer interface {
	Render(io.Writer) error
}

Renderer can be used with github.com/maragudk/gomponents Example:

func getRecipes(ctx fuego.ContextNoBody) (fuego.CtxRenderer, error) {
	recipes, err := ctx.store.GetRecipes(ctx.Context())
	if err != nil {
		return nil, err
	}

	return recipeComponent(recipes), nil // recipeComponent is gomponents component
}

type Route

type Route[ResponseBody any, RequestBody any] struct {
	BaseRoute
}

func All

func All[ReturnType, Body any, Contexted ctx[Body]](s *Server, path string, controller func(Contexted) (ReturnType, error), options ...func(*BaseRoute)) *Route[ReturnType, Body]

Capture all methods (GET, POST, PUT, PATCH, DELETE) and register a controller.

func AllStd

func AllStd(s *Server, path string, controller func(http.ResponseWriter, *http.Request), options ...func(*BaseRoute)) *Route[any, any]

func Delete

func Delete[T, B any, Contexted ctx[B]](s *Server, path string, controller func(Contexted) (T, error), options ...func(*BaseRoute)) *Route[T, B]

func DeleteStd

func DeleteStd(s *Server, path string, controller func(http.ResponseWriter, *http.Request), options ...func(*BaseRoute)) *Route[any, any]

func Get

func Get[T, B any, Contexted ctx[B]](s *Server, path string, controller func(Contexted) (T, error), options ...func(*BaseRoute)) *Route[T, B]

func GetStd

func GetStd(s *Server, path string, controller func(http.ResponseWriter, *http.Request), options ...func(*BaseRoute)) *Route[any, any]

func Handle

func Handle(s *Server, path string, controller http.Handler, options ...func(*BaseRoute)) *Route[any, any]

Handle registers a standard HTTP handler into the default mux. Use this function if you want to use a standard HTTP handler instead of a Fuego controller.

func Patch

func Patch[T, B any, Contexted ctx[B]](s *Server, path string, controller func(Contexted) (T, error), options ...func(*BaseRoute)) *Route[T, B]

func PatchStd

func PatchStd(s *Server, path string, controller func(http.ResponseWriter, *http.Request), options ...func(*BaseRoute)) *Route[any, any]

func Post

func Post[T, B any, Contexted ctx[B]](s *Server, path string, controller func(Contexted) (T, error), options ...func(*BaseRoute)) *Route[T, B]

func PostStd

func PostStd(s *Server, path string, controller func(http.ResponseWriter, *http.Request), options ...func(*BaseRoute)) *Route[any, any]

func Put

func Put[T, B any, Contexted ctx[B]](s *Server, path string, controller func(Contexted) (T, error), options ...func(*BaseRoute)) *Route[T, B]

func PutStd

func PutStd(s *Server, path string, controller func(http.ResponseWriter, *http.Request), options ...func(*BaseRoute)) *Route[any, any]

func Register

func Register[T, B any](s *Server, route Route[T, B], controller http.Handler, options ...func(*BaseRoute)) *Route[T, B]

Register registers a controller into the default mux and documents it in the OpenAPI spec.

func (Route[ResponseBody, RequestBody]) AddError deprecated

func (r Route[ResponseBody, RequestBody]) AddError(code int, description string, errorType ...any) Route[ResponseBody, RequestBody]

AddError adds an error to the route.

Deprecated: Use `option.AddError` from github.com/go-fuego/fuego/option instead.

func (Route[ResponseBody, RequestBody]) AddTags deprecated

func (r Route[ResponseBody, RequestBody]) AddTags(tags ...string) Route[ResponseBody, RequestBody]

AddTags adds tags to the route.

Deprecated: Use `option.Tags` from github.com/go-fuego/fuego/option instead. Example:

fuego.Get(s, "/test", testController, option.Tags("my-tag"))

func (Route[ResponseBody, RequestBody]) Cookie deprecated

func (r Route[ResponseBody, RequestBody]) Cookie(name, description string, params ...OpenAPIParamOption) Route[ResponseBody, RequestBody]

Cookie registers a cookie parameter for the route.

Deprecated: Use `option.Cookie` from github.com/go-fuego/fuego/option instead. Example:

fuego.Get(s, "/test", testController, option.Cookie("my-cookie", "my description"))

func (Route[ResponseBody, RequestBody]) Deprecated deprecated

func (r Route[ResponseBody, RequestBody]) Deprecated() Route[ResponseBody, RequestBody]

Deprecated marks the route as deprecated.

Deprecated: Use `option.Deprecated` from github.com/go-fuego/fuego/option instead. Example:

fuego.Get(s, "/test", testController, option.Deprecated())

func (Route[ResponseBody, RequestBody]) Description deprecated

func (r Route[ResponseBody, RequestBody]) Description(description string) Route[ResponseBody, RequestBody]

Overrides the description for the route.

Deprecated: Use `option.Description` from github.com/go-fuego/fuego/option instead. Example:

fuego.Get(s, "/test", testController, option.Description("my description"))

func (Route[ResponseBody, RequestBody]) Header deprecated

func (r Route[ResponseBody, RequestBody]) Header(name, description string, params ...OpenAPIParamOption) Route[ResponseBody, RequestBody]

Header registers a header parameter for the route.

Deprecated: Use `option.Header` from github.com/go-fuego/fuego/option instead. Example:

fuego.Get(s, "/test", testController, option.Header("my-header", "my description"))

func (Route[T, B]) NameFromNamespace

func (r Route[T, B]) NameFromNamespace(opts ...func(string) string) string

NameFromNamespace returns the Route's FullName final string delimited by `.`. Essentially getting the name of the function and leaving the package path

The output can be further modified with a list of optional string manipulation funcs (i.e func(string) string)

func (Route[ResponseBody, RequestBody]) OperationID deprecated

func (r Route[ResponseBody, RequestBody]) OperationID(operationID string) Route[ResponseBody, RequestBody]

Overrides the operationID for the route.

Deprecated: Use `option.OperationID` from github.com/go-fuego/fuego/option instead. Example:

fuego.Get(s, "/test", testController, option.OperationID("my-operation-id"))

func (Route[ResponseBody, RequestBody]) Param

func (r Route[ResponseBody, RequestBody]) Param(paramType ParamType, name, description string, params ...OpenAPIParamOption) Route[ResponseBody, RequestBody]

Param registers a parameter for the route. The paramType can be "query", "header" or "cookie" as defined in ParamType. [Cookie], [Header], [QueryParam] are shortcuts for Param.

func (Route[ResponseBody, RequestBody]) QueryParam deprecated

func (r Route[ResponseBody, RequestBody]) QueryParam(name, description string, params ...OpenAPIParamOption) Route[ResponseBody, RequestBody]

QueryParam registers a query parameter for the route.

Deprecated: Use `option.Query` from github.com/go-fuego/fuego/option instead. Example:

fuego.Get(s, "/test", testController, option.Query("my-param", "my description"))

func (Route[ResponseBody, RequestBody]) RemoveTags

func (r Route[ResponseBody, RequestBody]) RemoveTags(tags ...string) Route[ResponseBody, RequestBody]

RemoveTags removes tags from the route.

func (Route[ResponseBody, RequestBody]) RequestContentType deprecated

func (r Route[ResponseBody, RequestBody]) RequestContentType(consumes ...string) Route[ResponseBody, RequestBody]

Replace the available request Content-Types for the route. By default, the request Content-Types are `application/json` and `application/xml`

Deprecated: Use `option.RequestContentType` from github.com/go-fuego/fuego/option instead. Example:

fuego.Post(s, "/test", testControllerWithBody, option.RequestContentType("application/json"))

func (Route[ResponseBody, RequestBody]) Summary deprecated

func (r Route[ResponseBody, RequestBody]) Summary(summary string) Route[ResponseBody, RequestBody]

Overrides the summary for the route.

Deprecated: Use `option.Summary` from github.com/go-fuego/fuego/option instead. Example:

fuego.Get(s, "/test", testController, option.Summary("my summary"))

func (Route[ResponseBody, RequestBody]) Tags deprecated

func (r Route[ResponseBody, RequestBody]) Tags(tags ...string) Route[ResponseBody, RequestBody]

Replace the tags for the route. By default, the tag is the type of the response body.

Deprecated: Use `option.Tags` from github.com/go-fuego/fuego/option instead. Example:

fuego.Get(s, "/test", testController, option.Tags("my-tag"))

type SchemaTag

type SchemaTag struct {
	openapi3.SchemaRef
	Name string
}

SchemaTag is a struct that holds the name of the struct and the associated openapi3.SchemaRef

func SchemaTagFromType

func SchemaTagFromType(s *Server, v any) SchemaTag

type Security

type Security struct {
	Now             func() time.Time
	ExpiresInterval time.Duration
	// contains filtered or unexported fields
}

Security holds the key to sign the JWT tokens, and configuration information. The key isn't accessible once created to avoid leaking it. To use it, please use the methods provided.

func NewSecurity

func NewSecurity() Security

func (Security) CookieLogoutHandler

func (security Security) CookieLogoutHandler(w http.ResponseWriter, r *http.Request)

RemoveTokenFromCookies generates a JWT token with the given claims and writes it to the cookies. Usage:

fuego.PostStd(s, "/auth/logout", security.CookieLogoutHandler)

Dependency to Security is for symmetry with [RefreshHandler].

func (Security) GenerateToken

func (security Security) GenerateToken(claims jwt.Claims) (token string, err error)

GenerateToken generates a JWT token with the given claims. The claims must be a jwt.MapClaims or embed jwt.RegisteredClaims.

func (Security) GenerateTokenToCookies

func (security Security) GenerateTokenToCookies(claims jwt.Claims, w http.ResponseWriter) (string, error)

GenerateTokenToCookies generates a JWT token with the given claims and writes it to the cookies.

func (Security) LoginHandler

func (security Security) LoginHandler(verifyUserInfo func(user, password string) (jwt.Claims, error)) func(*ContextWithBody[LoginPayload]) (tokenResponse, error)

LoginHandler is a premade login handler. It takes a function that checks if the user is authorized. Example:

security := fuego.NewSecurity()
security.ExpiresInterval = 24 * time.Hour
fuego.Post(s, "/login", security.LoginHandler(verifyUserInfo))
...
func verifyUserInfo(r *http.Request) (jwt.Claims, error) {
	// Get the username and password from the request
	username := r.FormValue("username")
	password := r.FormValue("password")
	// ...
	// Check if the username and password are correct.
	// Usually, you would check in a database.
	if username != "myUsername" || password != "myPassword" {
		return nil, errors.New("invalid username or password")
	}
	// ...
	// Return the claims
	return &MyCustomToken{
		It is recommended to embed jwt.RegisteredClaims in your custom struct that will define your JWT.
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    username,
			Subject:   username,
			Audience:  jwt.ClaimStrings{"aud1", "aud2"},
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			ID:        "1234567890",
		},
		Username: "myUsername",
	}, nil

func (Security) RefreshHandler

func (security Security) RefreshHandler(w http.ResponseWriter, r *http.Request)

RefreshHandler is a premade refresh handler. It refreshes the token with the same information as the previous one, but with a new issued date. It sends the new token to the cookies and to the response. Usage:

fuego.PostStd(s, "/auth/refresh", security.RefreshHandler)

func (Security) StdLoginHandler

func (security Security) StdLoginHandler(verifyUserInfo func(r *http.Request) (jwt.Claims, error)) func(w http.ResponseWriter, r *http.Request)

StdLoginHandler is a premade login handler. It takes a function that checks if the user is authorized. Example:

security := fuego.NewSecurity()
security.ExpiresInterval = 24 * time.Hour
fuego.Post(s, "/login", security.StdLoginHandler(verifyUserInfo))
...
func verifyUserInfo(r *http.Request) (jwt.Claims, error) {
	// Get the username and password from the request
	username := r.FormValue("username")
	password := r.FormValue("password")
	// ...
	// Check if the username and password are correct.
	// Usually, you would check in a database.
	if username != "myUsername" || password != "myPassword" {
		return nil, errors.New("invalid username or password")
	}
	// ...
	// Return the claims
	return &MyCustomToken{
		It is recommended to embed jwt.RegisteredClaims in your custom struct that will define your JWT.
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    username,
			Subject:   username,
			Audience:  jwt.ClaimStrings{"aud1", "aud2"},
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			ID:        "1234567890",
		},
		Username: "myUsername",
	}, nil

func (Security) TokenToContext

func (security Security) TokenToContext(searchFunc ...func(*http.Request) string) func(next http.Handler) http.Handler

TokenToContext is a middleware that checks if the user is authenticated from various authentication methods. Once found, the token is parsed, validated and the claims are set in the context. TLDR: after this middleware, the token is either non-existent or validated. You can use TokenFromContext to get the claims

func (Security) ValidateToken

func (security Security) ValidateToken(token string) (*jwt.Token, error)

type Sender

type Sender func(http.ResponseWriter, *http.Request, any) error

type Server

type Server struct {
	// The underlying HTTP server
	*http.Server

	// Will be plugged into the Server field.
	// Not using directly the Server field so
	// [http.ServeMux.Handle] can also be used to register routes.
	Mux *http.ServeMux

	Listener    net.Listener
	TLSListener net.Listener

	OpenApiSpec openapi3.T // OpenAPI spec generated by the server

	Security Security

	DisallowUnknownFields bool // If true, the server will return an error if the request body contains unknown fields. Useful for quick debugging in development.
	DisableOpenapi        bool // If true, the routes within the server will not generate an OpenAPI spec.

	Serialize      Sender                // Custom serializer that overrides the default one.
	SerializeError ErrorSender           // Used to serialize the error response. Defaults to [SendError].
	ErrorHandler   func(err error) error // Used to transform any error into a unified error type structure with status code. Defaults to [ErrorHandler]

	OpenAPIConfig OpenAPIConfig
	// contains filtered or unexported fields
}

func Group

func Group(s *Server, path string, options ...func(*BaseRoute)) *Server

Group allows grouping routes under a common path. Middlewares are scoped to the group. For example:

s := fuego.NewServer()
viewsRoutes := fuego.Group(s, "")
apiRoutes := fuego.Group(s, "/api")
// Registering a middlewares scoped to /api only
fuego.Use(apiRoutes, myMiddleware)
// Registering a route under /api/users
fuego.Get(apiRoutes, "/users", func(c fuego.ContextNoBody) (ans, error) {
	return ans{Ans: "users"}, nil
})
s.Run()

func NewServer

func NewServer(options ...func(*Server)) *Server

NewServer creates a new server with the given options. For example:

app := fuego.NewServer(
	fuego.WithAddr(":8080"),
	fuego.WithoutLogger(),
)

Option all begin with `With`. Some default options are set in the function body.

func (*Server) AddTags

func (s *Server) AddTags(tags ...string) *Server

AddTags adds tags from the Server (i.e Group) Tags from the parent Groups will be respected

func (*Server) Cookie

func (s *Server) Cookie(name, description string, params ...OpenAPIParamOption) *Server

Registers a cookie param for all server routes.

func (*Server) Header

func (s *Server) Header(name, description string, params ...OpenAPIParamOption) *Server

Registers a header param for all server routes.

func (*Server) Hide

func (s *Server) Hide() *Server

Hide prevents the routes in this server or group from being included in the OpenAPI spec.

func (*Server) OutputOpenAPISpec

func (s *Server) OutputOpenAPISpec() openapi3.T

OutputOpenAPISpec takes the OpenAPI spec and outputs it to a JSON file and/or serves it on a URL. Also serves a Swagger UI. To modify its behavior, use the WithOpenAPIConfig option.

func (*Server) Param

func (s *Server) Param(name, description string, params ...OpenAPIParamOption) *Server

Registers a param for all server routes.

func (*Server) Query

func (s *Server) Query(name, description string, params ...OpenAPIParamOption) *Server

Registers a query param for all server routes.

func (*Server) RemoveTags

func (s *Server) RemoveTags(tags ...string) *Server

RemoveTags removes tags from the Server (i.e Group) if the parent Group(s) has matching tags they will be removed

func (*Server) Run

func (s *Server) Run() error

Run starts the server. It is blocking. It returns an error if the server could not start (it could not bind to the port for example). It also generates the OpenAPI spec and outputs it to a file, the UI, and a handler (if enabled).

func (*Server) RunTLS

func (s *Server) RunTLS(certFile, keyFile string) error

RunTLS starts the server with a TLS listener It is blocking. It returns an error if the server could not start (it could not bind to the port for example). It also generates the OpenAPI spec and outputs it to a file, the UI, and a handler (if enabled).

func (*Server) Show

func (s *Server) Show() *Server

Show allows displaying the routes. Activated by default so useless in most cases, but this can be useful if you deactivated the parent group.

func (*Server) Tags

func (s *Server) Tags(tags ...string) *Server

Replaces Tags for the Server (i.e Group) By default, the tag is the type of the response body.

type StdRenderer

type StdRenderer struct {
	// contains filtered or unexported fields
}

StdRenderer renders a template using the standard library templating engine.

func (StdRenderer) Render

func (s StdRenderer) Render(ctx context.Context, w io.Writer) error

type Templ

type Templ = CtxRenderer

Templ is a shortcut for CtxRenderer, which can be used with github.com/a-h/templ

type Timing

type Timing struct {
	Name string
	Dur  time.Duration
	Desc string
}

Timing is a struct to represent a server timing. Used in the Server-Timing header.

func (Timing) String

func (t Timing) String() string

String returns a string representation of a Timing, as defined in https://www.w3.org/TR/server-timing/#the-server-timing-header-field

type UnauthorizedError

type UnauthorizedError HTTPError

UnauthorizedError is an error used to return a 401 status code.

func (UnauthorizedError) Error

func (e UnauthorizedError) Error() string

func (UnauthorizedError) StatusCode

func (e UnauthorizedError) StatusCode() int

func (UnauthorizedError) Unwrap

func (e UnauthorizedError) Unwrap() error

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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