aether

package module
v0.1.6 Latest Latest
Warning

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

Go to latest
Published: Mar 23, 2026 License: MIT Imports: 23 Imported by: 0

README

⚡ Aether

A blazing-fast, type-safe Go web framework built on top of net/http with first-class Generics support.

Go Version

Features

  • 🧬 Generics-first — Type-safe global state, handlers, and middleware chains via Context[T]
  • 🔌 Pluggable engines — Bring your own JSON, XML, Template, and Cache engines
  • 🔒 Security built-in — Helmet, CORS, CSRF, Rate Limiter, JWT, and Basic Auth middlewares
  • Zero-alloc routing — Uses Go 1.22+ http.ServeMux with sync.Pool context recycling
  • 📡 SSE & WebSocket ready — Native support via http.ResponseController and Hijack()
  • Cron jobs — Built-in scheduler with graceful shutdown
  • 🗂️ net/http compatible — Wrap any standard func(http.Handler) http.Handler middleware
  • 🧪 Testable — Works directly with httptest out of the box
  • 🪵 High-performance logger — Async buffered logging with file output support

Quick Start

go get github.com/DantDev2102/aether
package main

import (
    "net/http"
    "github.com/DantDev2102/aether"
)

type AppState struct {
    Version string
}

func main() {
    app := aether.New(&aether.Config[AppState]{
        Port: 8080,
        Global: AppState{Version: "1.0.0"},
    })

    r := app.Router()

    aether.Get(r, "/", func(c *aether.Context[AppState]) {
        c.JSON(http.StatusOK, map[string]string{
            "message": "Hello from Aether!",
            "version": c.Global.Version,
        })
    })

    app.Listen()
}

Routing

r := app.Router()

// Simple routes
aether.Get(r, "/users", listUsers)
aether.Delete(r, "/users/{id}", deleteUser)

// Routes with automatic body binding
aether.Post[AppState, CreateUserBody](r, "/users", createUser)
aether.Put[AppState, UpdateUserBody](r, "/users/{id}", updateUser)
aether.Patch[AppState, PatchUserBody](r, "/users/{id}", patchUser)

// Route groups
api := aether.NewGroup("/api/v1", r)
aether.Get(api, "/health", healthCheck)

// Static files
aether.Static(r, "/assets/", "./public")

Context Helpers

// Path & query parameters
id := c.Param("id")
page := c.Query("page")

// Responses
c.JSON(200, data)
c.XML(200, data)
c.String(200, "Hello %s", name)
c.Render(200, "template_name", data)   // Requires configured TemplateEngine

// Files
c.File("/path/to/file.pdf")
c.Attachment("/path/to/file.pdf", "download.pdf")

// Cookies
c.SetCookie(&http.Cookie{Name: "session", Value: "abc"})
cookie, _ := c.Cookie("session")
c.ClearCookie("session")

// SSE
rc, _ := c.SSE()
fmt.Fprintf(c.Res(), "data: hello\n\n")
rc.Flush()

// WebSocket (via Hijack)
conn, bufrw, _ := c.Hijack()

// Cache
c.Cache().Set(ctx, "key", "value")
val, ok := c.Cache().Get(ctx, "key")

// Request/Response access for net/http interop
req := c.Req()
res := c.Res()

Middlewares

Built-in (root package)

Recovery and Logger middlewares are automatically applied.

Middleware Package
import "github.com/DantDev2102/aether/middlewares"

// CORS
r.Use(middlewares.CORSMiddleware[AppState](middlewares.CORSConfig{
    AllowOrigins: []string{"https://example.com"},
}))

// Helmet (Security Headers)
r.Use(middlewares.HelmetMiddleware[AppState](middlewares.DefaultHelmetConfig()))

// Rate Limiter
r.Use(middlewares.RateLimiterMiddleware[AppState](middlewares.RateLimiterConfig{
    Limit:  100,
    Window: time.Minute,
}))

// JWT Authentication
r.Use(middlewares.JWTMiddleware[AppState](middlewares.JWTConfig{
    Secret: []byte("your-secret-key"),
}))

// Basic Auth
r.Use(middlewares.BasicAuthMiddleware[AppState](middlewares.BasicAuthConfig{
    Users: map[string]string{"admin": "password"},
}))

// CSRF Protection
r.Use(middlewares.CSRFMiddleware[AppState](middlewares.CSRFConfig{}))

// Request ID
r.Use(middlewares.RequestIDMiddleware[AppState]())

// Gzip Compression
r.Use(middlewares.GzipMiddleware[AppState]())
Using net/http Middlewares
import "github.com/gorilla/handlers"

r.Use(aether.WrapMiddleware[AppState](handlers.RecoveryHandler()))

Cron Jobs

app.AddCron("cleanup", 1*time.Hour, func(ctx context.Context, log aether.Logger) {
    log.Info("Running cleanup...")
})

Cache

// Use the default Otter in-memory cache
store, _ := aether.NewOtterStore(10000)

app := aether.New(&aether.Config[AppState]{
    Cache: store,
})

// Or implement your own CacheStore interface
type CacheStore interface {
    Get(ctx context.Context, key string) (any, bool)
    Set(ctx context.Context, key string, value any) error
    Delete(ctx context.Context, key string) error
    Clear(ctx context.Context) error
}

Custom Engines

app := aether.New(&aether.Config[AppState]{
    JSON:     myCustomJSONEngine{},     // implements JSONEngine
    XML:      myCustomXMLEngine{},      // implements XMLEngine
    Template: myHandlebarsEngine{},     // implements TemplateEngine
    Cache:    myRedisStore{},           // implements CacheStore
    Logger:   myZapLogger{},            // implements Logger
})

Documentation

Full documentation is available in the docs/ directory:

Contributing

See CONTRIBUTING.md for guidelines.

License

MIT

Documentation

Index

Constants

View Source
const DefaultMaxBodySize = 2 << 20 // 2MB

DefaultMaxBodySize is the default maximum body size for incoming requests.

Variables

This section is empty.

Functions

func Connect

func Connect[T any](r *Router[T], path string, h HandlerFunc[T])

Connect registers a handler for CONNECT requests at the specified path.

func Delete

func Delete[T any](r *Router[T], path string, h HandlerFunc[T])

Delete registers a handler for DELETE requests at the specified path.

func Get

func Get[T any](r *Router[T], path string, h HandlerFunc[T])

Get registers a handler for GET requests at the specified path.

func Head[T any](r *Router[T], path string, h HandlerFunc[T])

Head registers a handler for HEAD requests at the specified path.

func Options

func Options[T any](r *Router[T], path string, h HandlerFunc[T])

Options registers a handler for OPTIONS requests at the specified path.

func Patch

func Patch[T, B any](r *Router[T], path string, h HandlerWithBody[T, B])

Patch registers a handler for PATCH requests at the specified path.

func Post

func Post[T, B any](r *Router[T], path string, h HandlerWithBody[T, B])

Post registers a handler for POST requests at the specified path.

func Put

func Put[T, B any](r *Router[T], path string, h HandlerWithBody[T, B])

Put registers a handler for PUT requests at the specified path.

func Static

func Static[T any](r *Router[T], pathPrefix, rootFolder string)

Static serves static files from the specified root folder.

func Trace

func Trace[T any](r *Router[T], path string, h HandlerFunc[T])

Trace registers a handler for TRACE requests at the specified path.

Types

type App

type App[T any] struct {
	// contains filtered or unexported fields
}

App represents the main Aether application instance.

func New

func New[T any](conf *Config[T]) *App[T]

New creates a new Aether application instance.

func (*App[T]) AddCron

func (a *App[T]) AddCron(name string, interval time.Duration, job CronJob)

AddCron registers a new cron job with the specified name and interval.

func (*App[T]) Listen

func (a *App[T]) Listen() error

Listen starts the Aether HTTP server and handles graceful shutdown.

func (*App[T]) Router

func (a *App[T]) Router() *Router[T]

Router returns the router instance.

type CacheStore

type CacheStore interface {
	Get(ctx context.Context, key string) (any, bool)
	Set(ctx context.Context, key string, value any) error
	Delete(ctx context.Context, key string) error
	Clear(ctx context.Context) error
}

CacheStore defines the interface for caching operations.

type Config

type Config[T any] struct {
	Port            int
	Host            string
	Timeout         int
	ShutdownTimeout int
	MaxBodyBytes    int64
	JSON            JSONEngine
	XML             XMLEngine
	Template        TemplateEngine
	Cache           CacheStore
	Logger          Logger
	Global          T
	ErrorHandler    CustomErrorHandler[T]
}

Config holds Aether configuration options.

type Context

type Context[T any] struct {
	Global T
	// contains filtered or unexported fields
}

Context holds the request context for a handler.

func (*Context[T]) Attachment

func (c *Context[T]) Attachment(filepath, filename string)

Attachment serves a file as an attachment with the specified filename.

func (*Context[T]) Bind

func (c *Context[T]) Bind(v any) error

Bind binds request body data to the specified struct based on content type.

func (*Context[T]) Cache

func (c *Context[T]) Cache() CacheStore

Cache returns the cache store instance.

func (*Context[T]) ClearCookie

func (c *Context[T]) ClearCookie(name string)

ClearCookie removes a cookie by setting its max age to -1.

func (*Context[T]) Cookie

func (c *Context[T]) Cookie(name string) (*http.Cookie, error)

Cookie returns the cookie with the specified name.

func (*Context[T]) File

func (c *Context[T]) File(filepath string)

File serves the file at the specified path.

func (*Context[T]) GetBody

func (c *Context[T]) GetBody() ([]byte, error)

GetBody reads and returns the request body.

func (*Context[T]) Hijack

func (c *Context[T]) Hijack() (net.Conn, *bufio.ReadWriter, error)

Hijack takes control of the underlying connection.

func (*Context[T]) JSON

func (c *Context[T]) JSON(status int, data any) error

JSON writes a JSON response with the specified status code.

func (*Context[T]) Log

func (c *Context[T]) Log() Logger

Log returns the logger instance.

func (*Context[T]) Next

func (c *Context[T]) Next()

Next executes the next handler in the middleware chain.

func (*Context[T]) Param

func (c *Context[T]) Param(key string) string

Param returns the path parameter value by key.

func (*Context[T]) Query

func (c *Context[T]) Query(key string) string

Query returns the query parameter value by key.

func (*Context[T]) Render

func (c *Context[T]) Render(status int, name string, data any) error

Render renders a template with the specified name and data.

func (*Context[T]) Req

func (c *Context[T]) Req() *http.Request

Req returns the current HTTP request.

func (*Context[T]) Res

func (c *Context[T]) Res() http.ResponseWriter

Res returns the current HTTP response writer.

func (*Context[T]) Reset

func (c *Context[T]) Reset(w http.ResponseWriter, req *http.Request, handlers []HandlerFunc[T], json JSONEngine, xml XMLEngine, template TemplateEngine, cache CacheStore, log Logger, global T)

Reset initializes or resets the context with new values.

func (*Context[T]) SSE

func (c *Context[T]) SSE() (*http.ResponseController, error)

SSE prepares the response for Server-Sent Events.

func (*Context[T]) SaveFile

func (c *Context[T]) SaveFile(file *multipart.FileHeader, dst string) error

SaveFile saves an uploaded file to the specified destination.

func (*Context[T]) SetCookie

func (c *Context[T]) SetCookie(cookie *http.Cookie)

SetCookie sets a cookie in the response.

func (*Context[T]) SetReq

func (c *Context[T]) SetReq(req *http.Request)

SetReq sets the current HTTP request.

func (*Context[T]) Start

func (c *Context[T]) Start() time.Time

Start returns the time when the request started.

func (*Context[T]) String

func (c *Context[T]) String(status int, text string, args ...any) error

func (*Context[T]) XML

func (c *Context[T]) XML(status int, data any) error

XML writes an XML response with the specified status code.

type CronJob

type CronJob func(ctx context.Context, log Logger)

CronJob is the function signature for cron job tasks.

type CronManager

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

CronManager manages scheduled cron jobs.

func (*CronManager) Add

func (c *CronManager) Add(name string, interval time.Duration, job CronJob)

Add registers a new cron job with the specified name and interval.

func (*CronManager) Start

func (c *CronManager) Start()

Start begins execution of all registered cron jobs.

func (*CronManager) Stop

func (c *CronManager) Stop()

Stop gracefully stops all running cron jobs.

type CustomContext

type CustomContext[T any, L any] struct {
	*Context[T]
	Data L
}

CustomContext extends Context with custom user data.

type CustomErrorHandler

type CustomErrorHandler[T any] func(c *Context[T], err any)

CustomErrorHandler defines the function signature for custom error handling.

type HandlerFunc

type HandlerFunc[T any] func(c *Context[T])

HandlerFunc is the function signature for HTTP handlers.

func LoggerMiddleware

func LoggerMiddleware[T any]() HandlerFunc[T]

LoggerMiddleware logs HTTP requests with method, path, status, and duration.

func RecoveryMiddleware

func RecoveryMiddleware[T any](customHandler CustomErrorHandler[T]) HandlerFunc[T]

RecoveryMiddleware recovers from panics and logs the error stack trace.

func WithCustomContext

func WithCustomContext[T, L any](initialData L, handler func(c *CustomContext[T, L])) HandlerFunc[T]

WithCustomContext creates a handler with custom context data.

func WrapMiddleware

func WrapMiddleware[T any](mw func(http.Handler) http.Handler) HandlerFunc[T]

WrapMiddleware adapts a standard net/http middleware into an Aether HandlerFunc.

type HandlerWithBody

type HandlerWithBody[T any, B any] func(c *Context[T], body B)

HandlerWithBody is the function signature for handlers that receive a request body.

type JSONEngine

type JSONEngine interface {
	Decode(r io.Reader, v any) error
	Encode(w io.Writer, v any) error
}

JSONEngine defines the interface for JSON encoding and decoding.

type LogConfig

type LogConfig struct {
	Stdout    bool
	FilePaths []string
	Level     slog.Level
}

LogConfig holds configuration options for the logger.

type Logger

type Logger interface {
	Debug(args ...any)
	Debugf(format string, args ...any)
	Info(args ...any)
	Infof(format string, args ...any)
	Warn(args ...any)
	Warnf(format string, args ...any)
	Error(args ...any)
	Errorf(format string, args ...any)
	Fatal(args ...any)
	Fatalf(format string, args ...any)
	Panic(args ...any)
	Panicf(format string, args ...any)
	Sync()
}

Logger defines the interface for logging operations.

func NewLogger

func NewLogger(cfg LogConfig) Logger

NewLogger creates a new Logger instance with the given configuration.

type OtterStore

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

OtterStore is a cache store implementation using the Otter library.

func NewOtterStore

func NewOtterStore(maxSize int) (*OtterStore, error)

NewOtterStore creates a new OtterStore with the specified maximum size.

func (*OtterStore) Clear

func (o *OtterStore) Clear(_ context.Context) error

Clear removes all entries from the cache.

func (*OtterStore) Delete

func (o *OtterStore) Delete(_ context.Context, key string) error

Delete removes a value from the cache by key.

func (*OtterStore) Get

func (o *OtterStore) Get(_ context.Context, key string) (any, bool)

Get retrieves a value from the cache by key.

func (*OtterStore) Set

func (o *OtterStore) Set(_ context.Context, key string, value any) error

Set stores a value in the cache with the specified key.

type ResponseWriter

type ResponseWriter interface {
	http.ResponseWriter
	Status() int
	Size() int
	Unwrap() http.ResponseWriter
}

ResponseWriter wraps http.ResponseWriter with status and size tracking.

type Router

type Router[T any] struct {
	// contains filtered or unexported fields
}

Router handles HTTP routing and middleware registration.

func NewGroup

func NewGroup[T any](prefix string, router *Router[T]) *Router[T]

NewGroup creates a new router group with the specified prefix.

func NewRouter

func NewRouter[T any](jsonEngine JSONEngine, xmlEngine XMLEngine, templateEngine TemplateEngine, cacheStore CacheStore, log Logger, global T, timeout int, maxBodyBytes int64) *Router[T]

NewRouter creates a new Router instance with the given configuration.

func (*Router[T]) ServeHTTP

func (r *Router[T]) ServeHTTP(w http.ResponseWriter, req *http.Request)

func (*Router[T]) Use

func (r *Router[T]) Use(middlewares ...HandlerFunc[T])

Use registers one or more middleware handlers.

type TemplateEngine

type TemplateEngine interface {
	Render(w io.Writer, name string, data any) error
}

TemplateEngine defines the interface for rendering templates.

type XMLEngine

type XMLEngine interface {
	Decode(r io.Reader, v any) error
	Encode(w io.Writer, v any) error
}

XMLEngine defines the interface for XML encoding and decoding.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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