A simple, fast, and flexible HTTP server framework for Go.
Zero dependencies on HTTP routing -- ships with its own lightweight router (gserv/router)HTTP/2 support -- enabled automatically via H2CMultiple codecs -- built-in JSON and MessagePack serializationSSE (Server-Sent Events) -- first-class support via gserv/sseGzip compression -- automatic when the client accepts gzipCaching middleware -- ETag-based response caching with configurable TTLRate limiting middleware -- per-key limits at second, minute, and hour granularityGroup-based routing -- organized route registration with inherited middleware chainsPanic recovery -- optional panic handler integration via oerrs frame capturego get go.oneofone.dev/gserv package main
import (
"context" "net/http" "os" "os/signal" "syscall" "go.oneofone.dev/gserv"
)
func main () {
srv := gserv .New ()
srv .GET ("/health" , func (ctx * gserv.Context ) gserv.Response {
return gserv .NewJSONResponse ("OK" )
})
srv .GET ("/users/:id" , func (ctx * gserv.Context ) gserv.Response {
id := ctx .Param ("id" )
return gserv .NewJSONResponse (map [string ]string {"id" : id })
})
ctx , cancel := signal .NotifyContext (context .Background (), syscall .SIGINT , syscall .SIGTERM )
defer cancel ()
go func () {
if err := srv .Run (ctx , ":8080" ); err != nil {
println (err .Error ())
}
}()
<- ctx .Done ()
srv .Shutdown (5 * time .Second )
}Grouped Routes with Middleware api := srv .SubGroup ("api" , "/api" , gserv .LogRequests (false ))
users := api .SubGroup ("users" , "/users" )
users .Use (authMiddleware ) // inherited by all routes in this subgroup users .GET ("" , listUsers )
users .GET ("/:id" , getUser )
users .POST ("" , createUser )
users .DELETE ("/:id" , deleteUser )func getUser (ctx * gserv.Context ) gserv.Response {
id := ctx .Param ("id" )
user , err := db .FindUser (id )
if err != nil {
return gserv .NewJSONErrorResponse (http .StatusInternalServerError , err )
}
if user == nil {
return gserv .NewJSONErrorResponse (http .StatusNotFound , "user not found" )
}
return gserv .NewJSONResponse (user )
}Request Binding (JSON and MessagePack) func createUser (ctx * gserv.Context ) gserv.Response {
var req struct {
Name string `json:"name"` Email string `json:"email"`
}
if err := ctx .Bind (& req ); err != nil {
return gserv .NewJSONErrorResponse (http .StatusBadRequest , err )
}
// ... handle request return gserv .NewJSONResponse (req )
}import "go.oneofone.dev/gserv/sse" sseRouter := sse .NewRouter ()
srv .GET ("/stream" , func (ctx * gserv.Context ) gserv.Response {
return sseRouter .Handle ("channel1" , 256 , ctx )
})
// Publish events from anywhere: go func () {
for {
sseRouter .Send ("channel1" , "" , "message" , map [string ]string {"text" : "hello" })
time .Sleep (time .Second )
}
}()srv .GET ("/products" , gserv .CacheHandler (
func (ctx * gserv.Context ) string {
return fmt .Sprintf ("products:lang=%s" , ctx .QueryDefault ("lang" , "en" ))
},
5 * time .Minute , // cache TTL listProducts , // cached handler
))// Limits: 10/second, 100/minute, 1000/hour per client IP rateLimiter := gserv .RateLimiter (ctx , nil , 10 , 100 , 1000 , true )
users .Use (rateLimiter )srv .Static ("/static" , "./public" , false ) // directory serving srv .StaticFile ("/favicon.ico" , "./assets/ico" ) // single file Type Content-Type Usage gserv.NewJSONResponse(data)application/jsonStandard JSON API response gserv.NewMsgpResponse(data)application/msgpackMessagePack serialization gserv.NewJSONErrorResponse(code, err)application/jsonError response with stack gserv.RespOKtext/plainCached 200 OK gserv.RespNotFoundapplication/jsonCached 404 gserv.File(ct, path)varies Serve a file
Method Description ctx.Param(key)URL path parameter ctx.Query(key)Query string parameter ctx.Bind(&v)Bind request body (auto-detects JSON/MsgPack) ctx.JSON(code, v)Write JSON response directly ctx.Msgpack(code, v)Write MsgPack response directly ctx.Get(key), ctx.Set(key, val)Typed context values ctx.ClientIP()Client IP (respects X-Real-Ip / X-Forwarded-For) ctx.File(path)Serve a file ctx.SetCookie(...)Set signed http-only cookie
srv := gserv .New (
gserv .ReadTimeout (time .Second * 30 ),
gserv .WriteTimeout (time .Minute ),
gserv .MaxHeaderBytes (1 << 20 ),
gserv .SetErrLogger (myLogger ),
gserv .SetCatchPanics (true ),
)AI was used to generate this README and some of the package's documentation. MIT