Skip to content

Repository files navigation

gserv

Go Reference

A simple, fast, and flexible HTTP server framework for Go.

Features

  • Zero dependencies on HTTP routing -- ships with its own lightweight router (gserv/router)
  • HTTP/2 support -- enabled automatically via H2C
  • Multiple codecs -- built-in JSON and MessagePack serialization
  • SSE (Server-Sent Events) -- first-class support via gserv/sse
  • Gzip compression -- automatic when the client accepts gzip
  • Caching middleware -- ETag-based response caching with configurable TTL
  • Rate limiting middleware -- per-key limits at second, minute, and hour granularity
  • Group-based routing -- organized route registration with inherited middleware chains
  • Panic recovery -- optional panic handler integration via oerrs frame capture

Installation

go get go.oneofone.dev/gserv

Quick Start

Basic Server

package main
import (
"context""net/http""os""os/signal""syscall""go.oneofone.dev/gserv"
)
funcmain() {
srv:=gserv.New()
srv.GET("/health", func(ctx*gserv.Context) gserv.Response {
returngserv.NewJSONResponse("OK")
})
srv.GET("/users/:id", func(ctx*gserv.Context) gserv.Response {
id:=ctx.Param("id")
returngserv.NewJSONResponse(map[string]string{"id": id})
})
ctx, cancel:=signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defercancel()
gofunc() {
iferr:=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 subgroupusers.GET("", listUsers)
users.GET("/:id", getUser)
users.POST("", createUser)
users.DELETE("/:id", deleteUser)

Typed JSON Responses

funcgetUser(ctx*gserv.Context) gserv.Response {
id:=ctx.Param("id")
user, err:=db.FindUser(id)
iferr!=nil {
returngserv.NewJSONErrorResponse(http.StatusInternalServerError, err)
}
ifuser==nil {
returngserv.NewJSONErrorResponse(http.StatusNotFound, "user not found")
}
returngserv.NewJSONResponse(user)
}

Request Binding (JSON and MessagePack)

funccreateUser(ctx*gserv.Context) gserv.Response {
varreqstruct {
Namestring`json:"name"`Emailstring`json:"email"`
}
iferr:=ctx.Bind(&req); err!=nil {
returngserv.NewJSONErrorResponse(http.StatusBadRequest, err)
}
// ... handle requestreturngserv.NewJSONResponse(req)
}

Server-Sent Events (SSE)

import"go.oneofone.dev/gserv/sse"sseRouter:=sse.NewRouter()
srv.GET("/stream", func(ctx*gserv.Context) gserv.Response {
returnsseRouter.Handle("channel1", 256, ctx)
})
// Publish events from anywhere:gofunc() {
for {
sseRouter.Send("channel1", "", "message", map[string]string{"text": "hello"})
time.Sleep(time.Second)
}
}()

Caching Middleware

srv.GET("/products", gserv.CacheHandler(
func(ctx*gserv.Context) string {
returnfmt.Sprintf("products:lang=%s", ctx.QueryDefault("lang", "en"))
},
5*time.Minute, // cache TTLlistProducts, // cached handler
))

Rate Limiting Middleware

// Limits: 10/second, 100/minute, 1000/hour per client IPrateLimiter:=gserv.RateLimiter(ctx, nil, 10, 100, 1000, true)
users.Use(rateLimiter)

Static Files

srv.Static("/static", "./public", false) // directory servingsrv.StaticFile("/favicon.ico", "./assets/ico") // single file

Response Types

TypeContent-TypeUsage
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)variesServe a file

Context API

MethodDescription
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

Server Configuration

srv:=gserv.New(
gserv.ReadTimeout(time.Second*30),
gserv.WriteTimeout(time.Minute),
gserv.MaxHeaderBytes(1<<20),
gserv.SetErrLogger(myLogger),
gserv.SetCatchPanics(true),
)

Trusted By

Disclaimer

  • AI was used to generate this README and some of the package's documentation.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages