Golang Fuego - Web framework generating OpenAPI 3 spec from source code - Pluggable to existing Gin & Echo APIs
See the code
The framework for busy Go developers
🚀 Explore and contribute to our 2025 Roadmap! 🚀
Production-ready Go API framework generating OpenAPI documentation from code. Inspired by Nest, built for Go developers.
Also empowers templating with html/template, a-h/templ and maragudk/gomponents:
see the example running live.
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.
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.net/http, with grouping and
middleware supportgo-playground/validatorfuego.InTransform and fuego.OutTransform interfaces - also useful for
custom validationnet/http middleware
or use the provided middlewares.html/template - you can still also use your own template system like
templ or gomponentspackage 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()
}
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, "/user/{user}", myController)
s.Run()
}
func myController(c fuego.ContextWithBody[MyInput]) (*MyOutput, error) {
body, err := c.Body()
if err != nil {
return nil, err
}
return &MyOutput{Message: "Hello, " + body.Name}, nil
}
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
}
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"
}
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()
}
Please see the /examples folder for more examples.
package main
import (
"context"
"errors"
"net/http"
"strings"
chiMiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/go-fuego/fuego"
"github.com/rs/cors"
)
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"}
https://github.com/go-fuego/fuego/assets/46993939/7438a71c-75a4-4e88-a584-71da6362c575
See the contributing guide. Thanks to everyone who has contributed to this project! ❤️
Made with contrib.rocks
See the board.
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.
Overall
Maintained
Code review
Go module
Latest release
Releases this year
(top 24 of 26)
176 followers · starred Jun 2026
203 followers · starred Oct 2025
629 followers · starred Oct 2024
121 followers · starred Feb 2024
Golang Fuego - Web framework generating OpenAPI 3 spec from source code - Pluggable to existing Gin & Echo APIs
See the code
The framework for busy Go developers
🚀 Explore and contribute to our 2025 Roadmap! 🚀
Production-ready Go API framework generating OpenAPI documentation from code. Inspired by Nest, built for Go developers.
Also empowers templating with html/template, a-h/templ and maragudk/gomponents:
see the example running live.
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.
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.net/http, with grouping and
middleware supportgo-playground/validatorfuego.InTransform and fuego.OutTransform interfaces - also useful for
custom validationnet/http middleware
or use the provided middlewares.html/template - you can still also use your own template system like
templ or gomponentspackage 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()
}
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, "/user/{user}", myController)
s.Run()
}
func myController(c fuego.ContextWithBody[MyInput]) (*MyOutput, error) {
body, err := c.Body()
if err != nil {
return nil, err
}
return &MyOutput{Message: "Hello, " + body.Name}, nil
}
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
}
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"
}
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()
}
Please see the /examples folder for more examples.
package main
import (
"context"
"errors"
"net/http"
"strings"
chiMiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/go-fuego/fuego"
"github.com/rs/cors"
)
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"}
https://github.com/go-fuego/fuego/assets/46993939/7438a71c-75a4-4e88-a584-71da6362c575
See the contributing guide. Thanks to everyone who has contributed to this project! ❤️
Made with contrib.rocks
See the board.
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.
Overall
Maintained
Code review
Go module
Latest release
Releases this year
(top 24 of 26)
176 followers · starred Jun 2026
203 followers · starred Oct 2025
629 followers · starred Oct 2024
121 followers · starred Feb 2024