haruka

package module
v0.0.0-...-e760721 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 21 Imported by: 7

README

haruka

web framework

Example

package main

import "github.com/allentom/haruka"

func main() {
	e := haruka.NewEngine()
	e.Router.GET("/ping", func(context *Context) {
		context.JSONWithStatus(haruka.JSON{
			"message":"Pong",
		}, http.StatusOK)
    })
	e.ListenAndServe(":8080")
}

Router

With specific path
e.Router.GET("/ping", <YourHandler>)
// with path parameters
e.Router.GET("/ping/{name}", <YourHandler>)
// with regex
e.Router.GET("/ping/{name:[0-9|a-z|A-Z]+}", <YourHandler>)
With different methods
e.Router.GET("/ping", <YourHandler>)
e.Router.POST("/ping", <YourHandler>)
e.Router.PATCH("/ping", <YourHandler>)
e.Router.Put("/ping", <YourHandler>)
e.Router.OPTION("/ping", <YourHandler>)

// for all methods
e.Router.AddHandler("/ping", <YourHandler>)
// for multiple methods
e.Router.METHODS("/ping", []string{"GET","POST"}, <YourHandler>)

Handler

Get query parameters
func (c *Context) {
    context.GetQueryString("id")
    context.GetQueryStrings("ids")
    context.GetQueryInt("id")
}
Get path parameters
func (c *Context) {
    context.GetPathParameterAsInt("id")
    context.GetPathParameterAsString("id")
}

Router Groups

Routes can share a prefix and a middleware chain. Groups nest; the effective chain is outermost-first.

api := e.Router.Group("/api", authMiddleware)
api.GET("/users", listUsers)

admin := api.Group("/admin", adminOnly)
admin.GET("/stats", stats) // /api/admin/stats

Middleware

A middleware implements OnRequest(*Context). It may also implement OnResponse(*Context) (interface ResponseMiddleware) to observe the response after the handler returns — invoked even when aborted or after a recovered panic.

Built-in middlewares (github.com/allentom/haruka/middleware):

Middleware Description
NewLoggerMiddleware Logs method, path, status, duration, ip and request id on response
&RequestIDMiddleware{} Assigns/propagates X-Request-ID, stores it in ctx.Param["requestId"]
NewTimeoutMiddleware(d) Sets a context deadline for the request
NewRateLimitMiddleware(rps, burst) Token bucket rate limiting keyed by client IP
NewGzipMiddleware() Transparent gzip response compression
NewBodyLimitMiddleware(n) Caps request body size
&CSRFMiddleware{} Double-submit cookie CSRF protection
NewJWTMiddleware JWT parsing (now powered by golang-jwt/jwt/v5)

Panic Recovery

Panics in handlers/middlewares are always recovered: the default handler logs the stack and renders a structured 500 error. A panic carrying an *HTTPError is rendered with its own status and message. Customize with:

haruka.SetRecoveryHandler(func(ctx *haruka.Context, panicValue interface{}) {
	// your rendering
})

Structured Errors

err := haruka.ErrNotFound("item vanished") // 404 + {"error":{"code":404,"message":"..."}}
ctx.JSONError(err)        // write envelope
ctx.AbortWithError(err)   // write envelope and abort chain

// or simply:
panic(haruka.ErrForbidden("no access"))

Server Lifecycle

e.RunAndListen(":8080")
e.RunAndListenTLS(":443", "cert.pem", "key.pem")
e.Shutdown(ctx)   // graceful drain
e.Stop()          // graceful shutdown, waits indefinitely

Engine.ReadHeaderTimeout guards slowloris-style connections (default 15s).

SSE (Server-Sent Events)

func handler(c *haruka.Context) {
	c.InitSSE()
	c.SendSSEEvent("progress", map[string]int{"p": 50})
	c.SendSSEData("done")
}

WebSocket

func handler(c *haruka.Context) {
	conn, err := c.UpgradeToWebSocket()
	// github.com/gorilla/websocket conn
}

Context Helpers

c.StatusCode()   // status written so far (0 = nothing yet)
c.ClientIP()     // X-Forwarded-For > X-Real-IP > RemoteAddr
c.StartTime()    // when the request entered the framework
e.Router.Routes() // registered route listing

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultWebSocketUpgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

DefaultWebSocketUpgrader is used by UpgradeToWebSocket. Replace or adjust CheckSameOrigin for stricter origin policies.

Functions

func BindingValue

func BindingValue(valueField reflect.Value, rawValue []string, tags reflect.StructTag) error

func SetRecoveryHandler

func SetRecoveryHandler(handler func(ctx *Context, panicValue interface{}))

SetRecoveryHandler replaces the built-in panic recovery handler. The default one logs the stack and renders a structured 500 error (or the panicked *HTTPError itself).

Types

type Context

type Context struct {
	// Pattern matched url path
	Pattern string
	// The http.ResponseWriter object.
	Writer http.ResponseWriter
	// The http.Request object.
	Request *http.Request
	// Path params
	Parameters map[string]string
	// For middleware to store dara
	Param map[string]interface{}
	// contains filtered or unexported fields
}

Context for request

func (*Context) Abort

func (c *Context) Abort()

interrupt middleware chain

func (*Context) AbortWithError

func (c *Context) AbortWithError(err *HTTPError)

AbortWithError writes err via JSONError and aborts the chain.

func (*Context) AbortWithStatus

func (c *Context) AbortWithStatus(status int)

AbortWithStatus writes the status code and aborts the chain.

func (*Context) AbortWithStatusJSON

func (c *Context) AbortWithStatusJSON(status int, data interface{})

AbortWithStatusJSON writes data as JSON with the given status and aborts the chain.

func (*Context) BindingInput

func (c *Context) BindingInput(input interface{}) error

func (*Context) ClientIP

func (c *Context) ClientIP() string

ClientIP resolves the client address honouring common proxy headers.

func (*Context) GetPathParameterAsInt

func (c *Context) GetPathParameterAsInt(key string) (int, error)

get path parameter as int

func (*Context) GetPathParameterAsString

func (c *Context) GetPathParameterAsString(key string) string

get path parameter as string

func (*Context) GetQueryInt

func (c *Context) GetQueryInt(key string) (int, error)

get query string as int

func (*Context) GetQueryString

func (c *Context) GetQueryString(key string) string

get query string from url

func (*Context) GetQueryStrings

func (c *Context) GetQueryStrings(key string) []string

get query string as []string

func (*Context) HTML

func (c *Context) HTML(templatePath string, data interface{}) (err error)

func (*Context) InitSSE

func (c *Context) InitSSE() error

InitSSE writes the event-stream headers and performs the first flush so browsers open the stream immediately.

func (*Context) JSON

func (c *Context) JSON(data interface{}) (err error)

func (*Context) JSONError

func (c *Context) JSONError(err *HTTPError) error

JSONError writes err as a structured JSON envelope:

{"error":{"code":400,"message":"..."}}

func (*Context) JSONWithStatus

func (c *Context) JSONWithStatus(data interface{}, status int) (err error)

func (*Context) ParseJson

func (c *Context) ParseJson(target interface{}) error

func (*Context) ParseXML

func (c *Context) ParseXML(target interface{}) error

func (*Context) RawWriter

func (c *Context) RawWriter() http.ResponseWriter

RawWriter exposes the original http.ResponseWriter before any framework wrapping. Needed when integration code must satisfy unexported interfaces of net/http (e.g. MaxBytesReader's 413 hook).

func (*Context) SendSSEData

func (c *Context) SendSSEData(data interface{}) error

SendSSEData writes a default (unnamed) event with JSON data.

func (*Context) SendSSEEvent

func (c *Context) SendSSEEvent(event string, data interface{}) error

SendSSEEvent writes a named event with JSON encoded data.

func (*Context) StartTime

func (c *Context) StartTime() time.Time

StartTime returns the moment the request entered the framework.

func (*Context) StatusCode

func (c *Context) StatusCode() int

StatusCode returns the HTTP status code written to the response, or 0 when nothing has been written yet.

func (*Context) UpgradeToWebSocket

func (c *Context) UpgradeToWebSocket() (*websocket.Conn, error)

UpgradeToWebSocket upgrades the current request to a WebSocket connection using DefaultWebSocketUpgrader.

func (*Context) UpgradeToWebSocketWith

func (c *Context) UpgradeToWebSocketWith(upgrader *websocket.Upgrader) (*websocket.Conn, error)

UpgradeToWebSocketWith upgrades the request with a custom upgrader.

func (*Context) XML

func (c *Context) XML(data interface{}) (err error)

func (*Context) XMLWithStatus

func (c *Context) XMLWithStatus(data interface{}, status int) (err error)

type Engine

type Engine struct {
	Router      *Router
	Middlewares []Middleware

	Logger *logrus.Logger
	Cros   *cors.Cors
	// ReadHeaderTimeout guards against slowloris attacks.
	// Zero means the default of 15 seconds.
	ReadHeaderTimeout time.Duration
	// ShutdownTimeout is the maximum time to wait for in-flight
	// requests during graceful shutdown. Zero means 10 seconds.
	ShutdownTimeout time.Duration
	// contains filtered or unexported fields
}

func NewEngine

func NewEngine() *Engine

func (*Engine) HTTPHandler

func (e *Engine) HTTPHandler() http.Handler

HTTPHandler assembles the final root http.Handler (CORS included).

func (*Engine) RunAndListen

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

func (*Engine) RunAndListenTLS

func (e *Engine) RunAndListenTLS(addr, certFile, keyFile string) error

RunAndListenTLS serves HTTPS. certFile/keyFile are PEM paths.

func (*Engine) Shutdown

func (e *Engine) Shutdown(ctx context.Context) error

Shutdown gracefully drains in-flight connections. The context controls the deadline; callers should not wait forever.

func (*Engine) ShutdownWithTimeout

func (e *Engine) ShutdownWithTimeout(timeout time.Duration) error

ShutdownWithTimeout gracefully drains in-flight connections, aborting after the given timeout.

func (*Engine) Stop

func (e *Engine) Stop() error

Stop gracefully shuts the server down using ShutdownTimeout (default 10s). It will never block indefinitely.

func (*Engine) UseCors

func (e *Engine) UseCors(cors *cors.Cors)

func (*Engine) UseMiddleware

func (e *Engine) UseMiddleware(middleware Middleware)

UseMiddleware registers a global middleware. It takes effect for requests handled after the call.

type FormFile

type FormFile struct {
	Header *multipart.FileHeader
	File   multipart.File
}

type Group

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

Group is a collection of routes sharing a common prefix and a common middleware chain. Groups can be nested; the effective chain is the concatenation of all ancestor chains (outermost first).

func (*Group) AddHandler

func (g *Group) AddHandler(pattern string, handler RequestHandler)

func (*Group) DELETE

func (g *Group) DELETE(pattern string, handler RequestHandler)

func (*Group) GET

func (g *Group) GET(pattern string, handler RequestHandler)

func (*Group) Group

func (g *Group) Group(prefix string, middlewares ...Middleware) *Group

Group creates a sub group with an extended prefix and additional middlewares.

func (*Group) METHODS

func (g *Group) METHODS(pattern string, methods []string, handler RequestHandler)

func (*Group) PATCH

func (g *Group) PATCH(pattern string, handler RequestHandler)

func (*Group) POST

func (g *Group) POST(pattern string, handler RequestHandler)

func (*Group) PUT

func (g *Group) PUT(pattern string, handler RequestHandler)

func (*Group) UseMiddleware

func (g *Group) UseMiddleware(middlewares ...Middleware)

UseMiddleware appends middlewares to the group chain. They only apply to routes registered after this call.

type HTMLView

type HTMLView struct {
	Data   []byte
	Writer io.Writer
	// contains filtered or unexported fields
}

func (*HTMLView) Render

func (v *HTMLView) Render(data interface{}) (err error)

func (*HTMLView) Write

func (v *HTMLView) Write(context *Context)

type HTTPError

type HTTPError struct {
	// StatusCode is the HTTP status written to the response.
	// It is not serialized into the body.
	StatusCode int `json:"-"`
	// Code is an application specific error code (optional).
	Code int `json:"code,omitempty"`
	// Message is a human readable description.
	Message string `json:"message"`
}

HTTPError is a structured API error. Handlers may return it to the client via JSONError / AbortWithError, or simply panic with it — the built-in recovery renders it with its status code.

func ErrBadRequest

func ErrBadRequest(message string) *HTTPError

func ErrForbidden

func ErrForbidden(message string) *HTTPError

func ErrInternal

func ErrInternal(message string) *HTTPError

func ErrNotFound

func ErrNotFound(message string) *HTTPError

func ErrUnauthorized

func ErrUnauthorized(message string) *HTTPError

func NewHTTPError

func NewHTTPError(statusCode int, message string) *HTTPError

func NewHTTPErrorWithCode

func NewHTTPErrorWithCode(statusCode, code int, message string) *HTTPError

func (*HTTPError) Error

func (e *HTTPError) Error() string

type JSON

type JSON map[string]interface{}

type JSONParser

type JSONParser struct {
}

func (*JSONParser) Parse

func (p *JSONParser) Parse(r *http.Request, target interface{}) error

type JsonView

type JsonView struct {
	Data []byte
}

func (*JsonView) Render

func (v *JsonView) Render(data interface{}) (err error)

func (*JsonView) Write

func (v *JsonView) Write(context *Context)

func (*JsonView) WriteWithStatus

func (v *JsonView) WriteWithStatus(context *Context, status int)

type Middleware

type Middleware interface {
	OnRequest(ctx *Context)
}

Middleware processes a request before it reaches the handler. Implementations may also implement ResponseMiddleware to receive a callback after the handler has finished.

type Parser

type Parser interface {
	Parse(r *http.Request, target interface{}) error
}

type RequestHandler

type RequestHandler func(context *Context)

type ResponseMiddleware

type ResponseMiddleware interface {
	OnResponse(ctx *Context)
}

ResponseMiddleware is an optional interface that a Middleware can implement to observe (or finalize) the response after the handler returns. It is invoked even when the chain was aborted or the handler panicked.

type RouteInfo

type RouteInfo struct {
	Pattern string
	Methods []string
}

RouteInfo describes a registered route, used for introspection.

type Router

type Router struct {
	Handlers      []RouterMapping
	HandlerRouter *mux.Router
	Middleware    []Middleware
	// contains filtered or unexported fields
}

func NewRouter

func NewRouter() *Router

func (*Router) AddHandler

func (r *Router) AddHandler(pattern string, handler RequestHandler)

func (*Router) DELETE

func (r *Router) DELETE(pattern string, handler RequestHandler)

func (*Router) GET

func (r *Router) GET(pattern string, handler RequestHandler)

func (*Router) Group

func (r *Router) Group(prefix string, middlewares ...Middleware) *Group

Group creates a route group sharing the given prefix and middlewares.

func (*Router) METHODS

func (r *Router) METHODS(pattern string, methods []string, handler RequestHandler)

func (*Router) MakeHandlerContext

func (r *Router) MakeHandlerContext(writer http.ResponseWriter, request *http.Request, pattern string) *Context

MakeHandlerContext builds a Context and runs the global middleware chain. It returns nil when the chain was aborted. Kept for backward compatibility; the internal dispatch path uses more features.

func (*Router) PATCH

func (r *Router) PATCH(pattern string, handler RequestHandler)

func (*Router) POST

func (r *Router) POST(pattern string, handler RequestHandler)

func (*Router) PUT

func (r *Router) PUT(pattern string, handler RequestHandler)

func (*Router) Prefix

func (r *Router) Prefix(pattern string, handler RequestHandler)

func (*Router) Routes

func (r *Router) Routes() []RouteInfo

Routes returns a snapshot of all registered routes.

func (*Router) Static

func (r *Router) Static(pattern string, staticPath string)

type RouterMapping

type RouterMapping struct {
	Pattern     string
	HandlerFunc RequestHandler
}

type View

type View interface {
	Render(data interface{}) (err error)
	Write(context *Context)
}

type XML

type XML map[string]interface{}

type XMLParser

type XMLParser struct {
}

func (*XMLParser) Parse

func (p *XMLParser) Parse(r *http.Request, target interface{}) error

type XMLView

type XMLView struct {
	Data []byte
}

func (*XMLView) Render

func (v *XMLView) Render(data interface{}) (err error)

func (*XMLView) Write

func (v *XMLView) Write(context *Context)

func (*XMLView) WriteWithStatus

func (v *XMLView) WriteWithStatus(context *Context, status int)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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