flare

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2026 License: MIT Imports: 13 Imported by: 0

README

flare

a small, fasthttp-backed router with a gin-like handler, batteries not included.

module: github.com/deglebe/flare

package main

import (
    "log"

    "github.com/deglebe/flare"
)

func main() {
    e := flare.New()
    e.Use(flare.Recover())

    e.GET("/health", func(c *flare.Ctx) {
        c.SetBodyString("ok")
    })
    e.GET("/users/:id", func(c *flare.Ctx) {
        c.JSON(200, map[string]string{"id": c.Param("id")})
    })

    log.Fatal(e.Listen(":8080"))
}

is it any good?

yes

install

go get github.com/deglebe/flare

requires a recent (>v1.20) go toolchain due to use of unsafe. for faster json encoding/decoding using bytedance's sonic (marginal boost on small apis):

go build -tags flare_sonic

examples

from the repo root:

go run ./examples/basic    # / /health /hello/:name
go run ./examples/api      # token-gated json crud
go run ./examples/static   # get / -> public/index.html
# basic
curl -s localhost:8080/hello/ada

# api (header required)
curl -s -H 'X-Token: secret' localhost:8080/api/users
curl -s -H 'X-Token: secret' -H 'Content-Type: application/json' \
  -d '{"name":"linus"}' localhost:8080/api/users

# static
curl -s localhost:8080/
curl -s localhost:8080/health

how it works

routing

each http method owns a radix tree (:param and *catchall). trailing slashes are strict: /a and /a/ are different routes. flare never redirects or strips them.

registration freezes on the first Handler()/Listen(). at freeze, flare:

  1. collapses an empty method root that has a single child (reduces hops per request by one)
  2. builds an exact-path table for static leaves so common paths skip walking the full tree.

the seven usual verbs use a fixed method index instead of a map. unknown methods panic at registration.

middleware and Ctx

Use and Group precompose middleware into each route's handler slice when the route is registered, meaning that there is no per-request stack rebuild. Next, Abort/AbortWithStatus/AbortWithStatusJSON, and Recover/RecoverWith follow the usual pattern.

each request borrows a pooled Ctx wrapping *fasthttp.RequestCtx. routes with a single leaf handler call it directly and skip the Next index loop.

requests and responses

helpers stay optional and off the match path:

params/query/headers Param, ParamInt, Query, GetHeader
json JSON, BindJSON (-tags flare_sonic optional)
forms Bind, BindForm
content negotiate Negotiate (html vs json stub)
files Static(prefix, dir)
client address ClientIP (see below)

Engine.Server is an embedded fasthttp.Server with conservative defaults (4 mib body, 10 s read/write, 60 s idle). override fields before Listen.

NoRoute / NoMethod distinguish unknown paths (404) from wrong methods on a known path (405).

client ip and proxies

by default ClientIP() returns the socket peer and ignores X-Forwarded-For/X-Real-IP. behind nginx or similar, you must allow the proxy hop explicitly:

_ = e.SetTrustedProxies("10.0.0.0/8", "127.0.0.1")
// optional: e.SetRemoteIPHeaders("X-Forwarded-For")

trusted peers may supply those headers; X-Forwarded-For is walked right-to-left, skipping hops that are also trusted.

scope

flare is meant to be a minimal router kernel on top of which to build an equally, if not more performant stack. so, flare is only match, groups, middleware, Ctx, bind/json helpers, static files, and listen/limits, until more is called for in core. sessions, oauth, openapi, orms, heavy validators, and cors/rate-limit packs are intentionally left out, though a companion library may include these features in the future.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrUnsupportedMediaType = errors.New("flare: unsupported media type")

Functions

func SetJSONCodec

func SetJSONCodec(marshal jsonMarshalFunc, unmarshal jsonUnmarshalFunc)

swaps json encode/decode

Types

type Accept

type Accept struct {
	JSON any
	HTML string
}

response negotiation set w/ json as default

type Ctx

type Ctx struct {
	*fasthttp.RequestCtx
	// contains filtered or unexported fields
}

func (*Ctx) Abort

func (c *Ctx) Abort()

func (*Ctx) AbortWithStatus

func (c *Ctx) AbortWithStatus(code int)

func (*Ctx) AbortWithStatusJSON

func (c *Ctx) AbortWithStatusJSON(code int, v any)

func (*Ctx) Bind

func (c *Ctx) Bind(v any) error

Bind decodes the body from content-type (json or form-urlencoded) call from handlers only, not from router hot path

func (*Ctx) BindForm

func (c *Ctx) BindForm(v any) error

fills exported string/int fields from post args (form, else join, else name) reflect-based, also keep off hot path

func (*Ctx) BindJSON

func (c *Ctx) BindJSON(v any) error

func (*Ctx) ClientIP

func (c *Ctx) ClientIP() string

returns client address if socket peer is listed in SetTrustedProxies, headers from SetRemoteIPHeaders are consulted w/o anything configured headers are ignored and the peer address is returned

func (*Ctx) GetHeader

func (c *Ctx) GetHeader(key string) string

func (*Ctx) IsAborted

func (c *Ctx) IsAborted() bool

func (*Ctx) JSON

func (c *Ctx) JSON(code int, v any)

func (*Ctx) Negotiate

func (c *Ctx) Negotiate(code int, a Accept)

writes html when accept prefers it and html is set, otherwise json

func (*Ctx) Next

func (c *Ctx) Next()

func (*Ctx) Param

func (c *Ctx) Param(key string) string

func (*Ctx) ParamInt

func (c *Ctx) ParamInt(key string) (int, error)

func (*Ctx) Query

func (c *Ctx) Query(key string) string

type Engine

type Engine struct {

	// holds fasthttp limits/timeouts
	Server fasthttp.Server
	// contains filtered or unexported fields
}

this is a fasthttp router trailing slashes are significant and never redirected/stripped

func New

func New() *Engine

func (*Engine) DELETE

func (e *Engine) DELETE(path string, h ...Handler)

func (*Engine) GET

func (e *Engine) GET(path string, h ...Handler)

func (*Engine) Group

func (e *Engine) Group(prefix string, mws ...Handler) *Router

func (*Engine) HEAD

func (e *Engine) HEAD(path string, h ...Handler)

func (*Engine) Handler

func (e *Engine) Handler() fasthttp.RequestHandler

func (*Engine) Listen

func (e *Engine) Listen(addr string) error

func (*Engine) NoMethod

func (e *Engine) NoMethod(h ...Handler)

func (*Engine) NoRoute

func (e *Engine) NoRoute(h ...Handler)

func (*Engine) OPTIONS

func (e *Engine) OPTIONS(path string, h ...Handler)

func (*Engine) PATCH

func (e *Engine) PATCH(path string, h ...Handler)

func (*Engine) POST

func (e *Engine) POST(path string, h ...Handler)

func (*Engine) PUT

func (e *Engine) PUT(path string, h ...Handler)

func (*Engine) SetRemoteIPHeaders

func (e *Engine) SetRemoteIPHeaders(headers ...string)

overrides header list used when peer is trusted defaults restored with nothing passed

func (*Engine) SetTrustedProxies

func (e *Engine) SetTrustedProxies(proxies ...string) error

set cidrs/bare ips allowed to supply forwarded-client headers empty means clientip always returns sock peer

func (*Engine) Static

func (e *Engine) Static(prefix, rootDir string)

serve from rootdir under prefix (get+head) prefix / serves the directory at the site root

func (*Engine) Use

func (e *Engine) Use(mws ...Handler)

type Handler

type Handler func(*Ctx)

func Recover

func Recover() Handler

catch panic, log, respond 500

func RecoverWith

func RecoverWith(fn func(*Ctx, any)) Handler

Recover+panic hook

type Router

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

func (*Router) DELETE

func (r *Router) DELETE(path string, h ...Handler)

func (*Router) GET

func (r *Router) GET(path string, h ...Handler)

func (*Router) Group

func (r *Router) Group(prefix string, mws ...Handler) *Router

func (*Router) HEAD

func (r *Router) HEAD(path string, h ...Handler)

func (*Router) PATCH

func (r *Router) PATCH(path string, h ...Handler)

func (*Router) POST

func (r *Router) POST(path string, h ...Handler)

func (*Router) PUT

func (r *Router) PUT(path string, h ...Handler)

func (*Router) Static

func (r *Router) Static(prefix, rootDir string)

mount Engine.Static under this group's prefix

func (*Router) Use

func (r *Router) Use(mws ...Handler)

Directories

Path Synopsis
examples
api command
basic command
static command

Jump to

Keyboard shortcuts

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