Gin — API Surface#
API types#
Library — Gin is a pure Go HTTP framework library. It exposes no CLI, no gRPC surface, and no plugin binary protocol. Its entire public API is consumed programmatically by application code. There are two integration layers: the primary object-oriented API (gin.Engine / gin.RouterGroup / gin.Context) and a thin singleton wrapper (ginS package) for quick scripts.
Library API#
Public packages#
| Package | Role |
|---|---|
github.com/gin-gonic/gin | Core: Engine, RouterGroup, Context, middleware constructors, type definitions |
github.com/gin-gonic/gin/binding | Binding interfaces + singleton instances (JSON, XML, Form, Query, YAML, TOML, ProtoBuf, MsgPack, BSON, URI, Header, Plain) |
github.com/gin-gonic/gin/render | Render interface + render implementations (JSON, XML, HTML, YAML, TOML, ProtoBuf, MsgPack, BSON, SSE, Redirect, Data, String) |
github.com/gin-gonic/gin/codec/json | Swappable JSON backend (Core interface; implementations: stdlib, jsoniter, sonic, go-json) |
github.com/gin-gonic/gin/ginS | Singleton wrapper that delegates every Engine method to a lazily-initialized global gin.Default() engine |
Engine construction#
// Bare engine — no default middleware
engine := gin.New(optFns ...OptionFunc) *Engine
// Engine with Logger + Recovery middleware pre-attached
engine := gin.Default(optFns ...OptionFunc) *EngineOptionFunc func(*Engine) — functional options applied at construction time. Built-in options:
gin.WithMaxMultipartMemory(bytes int64)— configures multipart parse limit
Engine fields configurable after creation (direct struct assignment):
RedirectTrailingSlash bool(default true)RedirectFixedPath boolHandleMethodNotAllowed boolForwardedByClientIP boolUseRawPath boolUnescapePathValues boolMaxMultipartMemory int64UseH2C bool— enable HTTP/2 cleartextContextWithFallback bool— letc.Value(key)fall through toc.Request.Context()
Route registration#
Gin’s routing API is exposed via two interfaces:
IRoutes (routergroup.go:33):
type IRoutes interface {
Use(...HandlerFunc) IRoutes
Handle(string, string, ...HandlerFunc) IRoutes
Any(string, ...HandlerFunc) IRoutes
GET(string, ...HandlerFunc) IRoutes
POST(string, ...HandlerFunc) IRoutes
DELETE(string, ...HandlerFunc) IRoutes
PATCH(string, ...HandlerFunc) IRoutes
PUT(string, ...HandlerFunc) IRoutes
OPTIONS(string, ...HandlerFunc) IRoutes
HEAD(string, ...HandlerFunc) IRoutes
Match([]string, string, ...HandlerFunc) IRoutes
StaticFile(string, string) IRoutes
StaticFileFS(string, string, http.FileSystem) IRoutes
Static(string, string) IRoutes
StaticFS(string, http.FileSystem) IRoutes
}IRouter (routergroup.go:27) extends IRoutes with:
Group(string, ...HandlerFunc) *RouterGroupBoth *Engine and *RouterGroup implement IRouter. The difference is that engine.Use() returns *Engine while group.Use() returns *RouterGroup — controlled by the returnObj() helper that checks group.root.
Route path syntax:
- Named parameter:
/users/:id— captured asc.Param("id") - Wildcard:
/static/*filepath— captures remainder including slashes - Escaped colon:
/items/::sku— literal colon in path (post-processed viasync.Once) - Custom:
Handle(httpMethod, path, handlers...)accepts any uppercase ASCII method name
Handler variadic convention: all registration methods accept ...HandlerFunc. All but the last are treated as route-scoped middleware; the last is the terminal handler. In practice any HandlerFunc in the chain can call c.Next() to delegate or c.Abort() to short-circuit.
Middleware registration#
Type: HandlerFunc func(*Context) — the same type used for both middleware and terminal handlers. This is the core design choice: no separate middleware type.
Global (engine-level):
engine.Use(Logger(), Recovery(), rateLimiter)Group-scoped:
v1 := engine.Group("/api/v1", authMiddleware)
v1.Use(rateLimiter)Route-scoped (inline):
engine.GET("/admin", authMiddleware, adminHandler)All three forms ultimately concatenate HandlerFunc slices using RouterGroup.combineHandlers(). The resulting chain is stored in the radix tree node at registration time, so there is no per-request chain assembly overhead.
Built-in middleware constructors:
| Constructor | File | Description |
|---|---|---|
Logger() HandlerFunc | logger.go:224 | Colorized request/response logging to stdout |
LoggerWithConfig(conf LoggerConfig) HandlerFunc | logger.go:245 | Configurable logger (custom formatter, writer, skip paths) |
LoggerWithFormatter(f LogFormatter) HandlerFunc | logger.go:229 | Logger with custom format function |
LoggerWithWriter(out io.Writer, skip ...string) HandlerFunc | logger.go:237 | Logger to arbitrary writer |
ErrorLogger() HandlerFunc | logger.go:207 | Logs only requests that returned errors |
ErrorLoggerT(typ ErrorType) HandlerFunc | logger.go:212 | Filtered error logger by error type |
Recovery() HandlerFunc | recovery.go:35 | Panic recovery → 500 response |
CustomRecovery(handle RecoveryFunc) HandlerFunc | recovery.go:40 | Recovery with custom panic handler |
RecoveryWithWriter(out io.Writer, ...) HandlerFunc | recovery.go:45 | Recovery logging to arbitrary writer |
CustomRecoveryWithWriter(out, handle) HandlerFunc | recovery.go:53 | Full custom recovery |
BasicAuth(accounts Accounts) HandlerFunc | auth.go:72 | HTTP Basic Auth |
BasicAuthForRealm(accounts, realm) HandlerFunc | auth.go:48 | Basic Auth with custom realm |
BasicAuthForProxy(accounts, realm) HandlerFunc | auth.go:98 | Proxy authentication header |
Context API#
*gin.Context is the sole argument to every HandlerFunc. It is the user-facing API for everything that happens inside a handler. It is pooled via sync.Pool and reset between requests.
Chain control:
c.Next() // advance to next handler in chain
c.Abort() // stop chain (sets index to abortIndex)
c.AbortWithStatus(code int)
c.AbortWithStatusJSON(code int, jsonObj any)
c.AbortWithStatusPureJSON(code int, jsonObj any)
c.AbortWithError(code int, err error) *Error
c.IsAborted() boolRequest reading:
// Path parameters
c.Param(key string) string
// Query string
c.Query(key string) string
c.DefaultQuery(key, defaultValue string) string
c.GetQuery(key string) (string, bool)
c.QueryArray(key string) []string
c.QueryMap(key string) map[string]string
// POST form
c.PostForm(key string) string
c.DefaultPostForm(key, defaultValue string) string
c.PostFormArray(key string) []string
c.PostFormMap(key string) map[string]string
// Files
c.FormFile(name string) (*multipart.FileHeader, error)
c.MultipartForm() (*multipart.Form, error)
// Raw body
c.GetRawData() ([]byte, error)
// Headers / metadata
c.GetHeader(key string) string
c.ContentType() string
c.ClientIP() string
c.RemoteIP() string
c.IsWebsocket() bool
c.Cookie(name string) (string, error)Binding (auto-detect from Content-Type + validation):
// Panics on error (returns 400 automatically)
c.Bind(obj any) error // auto-detect binding
c.BindJSON(obj any) error
c.BindXML(obj any) error
c.BindQuery(obj any) error
c.BindYAML(obj any) error
c.BindTOML(obj any) error
c.BindPlain(obj any) error
c.BindHeader(obj any) error
c.BindUri(obj any) error
// Error-only (does NOT abort on failure)
c.ShouldBind(obj any) error
c.ShouldBindJSON(obj any) error
c.ShouldBindXML(obj any) error
c.ShouldBindQuery(obj any) error
c.ShouldBindYAML(obj any) error
c.ShouldBindTOML(obj any) error
c.ShouldBindPlain(obj any) error
c.ShouldBindHeader(obj any) error
c.ShouldBindUri(obj any) error
c.ShouldBindWith(obj any, b binding.Binding) error
c.ShouldBindBodyWith(obj any, bb binding.BindingBody) error // caches body for re-use
c.ShouldBindBodyWithJSON/XML/YAML/TOML/Plain(obj any) errorResponse writing:
// Structured responses
c.JSON(code int, obj any)
c.IndentedJSON(code int, obj any)
c.SecureJSON(code int, obj any) // prevents JSON hijacking
c.PureJSON(code int, obj any) // no HTML escaping
c.AsciiJSON(code int, obj any) // non-ASCII characters escaped
c.JSONP(code int, obj any)
c.XML(code int, obj any)
c.YAML(code int, obj any)
c.TOML(code int, obj any)
c.ProtoBuf(code int, obj any)
c.BSON(code int, obj any)
c.PDF(code int, data []byte)
// HTML templates
c.HTML(code int, name string, obj any)
// Text/binary
c.String(code int, format string, values ...any)
c.Data(code int, contentType string, data []byte)
c.DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string)
// Files
c.File(filepath string)
c.FileFromFS(filepath string, fs http.FileSystem)
c.FileAttachment(filepath, filename string) // Content-Disposition: attachment
// Streaming / SSE
c.SSEvent(name string, message any)
c.Stream(step func(w io.Writer) bool) bool
// Redirect
c.Redirect(code int, location string)
// Content negotiation
c.Negotiate(code int, config Negotiate)
c.NegotiateFormat(offered ...string) string
// Low-level
c.Render(code int, r render.Render)
c.Status(code int)
c.Header(key, value string)
c.SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)
c.SetCookieData(cookie *http.Cookie)
c.SetSameSite(samesite http.SameSite)Per-request key/value store (middleware communication channel):
c.Set(key any, value any)
c.Get(key any) (value any, exists bool)
c.MustGet(key any) any
c.Delete(key any)
// Typed getters (avoid type assertions in handlers)
c.GetString(key any) string
c.GetBool(key any) bool
c.GetInt(key any) int
c.GetInt64(key any) int64
c.GetFloat64(key any) float64
c.GetTime(key any) time.Time
c.GetDuration(key any) time.Duration
c.GetStringSlice(key any) []string
c.GetStringMap(key any) map[string]any
// ... and many more typed variants for all numeric typesError accumulation:
c.Error(err error) *Error // attach error to request; doesn't abort
// Retrieve in middleware: c.Errors (type ErrorMsgs)context.Context implementation:
*Context implements context.Context (Deadline, Done, Err, Value), delegating to c.Request.Context() when ContextWithFallback is enabled. This allows passing c directly to libraries that accept context.Context.
Miscellaneous:
c.Copy() *Context // safe copy for use in goroutines
c.HandlerName() string // name of current handler function
c.HandlerNames() []string // all handler names in chain
c.FullPath() string // matched route pattern (e.g. "/users/:id")
c.AddParam(key, value string) // inject path param (testing/mocking)Engine server API#
// HTTP/1.1
engine.Run(addr ...string) error // wraps http.ListenAndServe
engine.RunTLS(addr, certFile, keyFile string) error
engine.RunUnix(file string) error
engine.RunFd(fd int) error
engine.RunListener(listener net.Listener) error
// HTTP/2
engine.Handler() http.Handler // returns h2c-wrapped handler when UseH2C=true
// HTTP/3 (QUIC)
engine.RunQUIC(addr, certFile, keyFile string) error
// Programmatic dispatch (testing / forwarding)
engine.ServeHTTP(w http.ResponseWriter, req *http.Request)
engine.HandleContext(c *Context) // re-dispatch a Context (useful for 404/405 rewrites)Engine configuration API#
engine.SetTrustedProxies([]string{...}) error // CIDR list or nil (trust all) or empty (trust none)
engine.NoRoute(handlers ...HandlerFunc) // custom 404 handler
engine.NoMethod(handlers ...HandlerFunc) // custom 405 handler
engine.Routes() RoutesInfo // enumerate registered routes
engine.With(opts ...OptionFunc) *Engine // apply options post-construction
// HTML templates
engine.LoadHTMLGlob(pattern string)
engine.LoadHTMLFiles(files ...string)
engine.LoadHTMLFS(fs http.FileSystem, patterns ...string)
engine.SetHTMLTemplate(templ *template.Template)
engine.SetFuncMap(funcMap template.FuncMap)
engine.Delims(left, right string) *Engine
engine.SecureJsonPrefix(prefix string) *EngineGlobal configuration API (package-level)#
gin.SetMode(value string) // "debug" | "release" | "test" (or GIN_MODE env)
gin.Mode() string
gin.IsDebugging() bool
gin.DisableBindValidation() // skip go-playground/validator
gin.EnableJsonDecoderUseNumber() // json.Number instead of float64
gin.EnableJsonDecoderDisallowUnknownFields()
gin.DisableConsoleColor()
gin.ForceConsoleColor()Static file API#
// Single file
group.StaticFile("/favicon.ico", "./resources/favicon.ico") IRoutes
group.StaticFileFS("/favicon.ico", "./resources/favicon.ico", fs) IRoutes
// Directory
group.Static("/static", "/var/www") IRoutes
group.StaticFS("/static", customFS) IRoutes
// Utility
gin.Dir(root string, listDirectory bool) http.FileSystemStdlib interop utilities#
gin.WrapF(f http.HandlerFunc) HandlerFunc // adapt stdlib HandlerFunc for use in gin chain
gin.WrapH(h http.Handler) HandlerFunc // adapt stdlib Handler for use in gin chain
gin.Bind(val any) HandlerFunc // create a middleware that binds request into valTesting API#
gin.CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine)
gin.CreateTestContextOnly(w http.ResponseWriter, r *Engine) *ContextBoth are in test_helpers.go. They construct a live Context and Engine attached to the provided http.ResponseWriter, enabling unit testing of handlers without starting a TCP server. Combined with httptest.NewRecorder(), this is the idiomatic testing pattern.
ginS — singleton wrapper#
github.com/gin-gonic/gin/ginS re-exports every route/middleware/server method as package-level functions backed by a lazily-initialized global gin.Default() engine (sync.OnceValue). This allows zero-setup script-style usage:
ginS.GET("/ping", func(c *gin.Context) { c.String(200, "pong") })
ginS.Run(":8080")The singleton is intentionally unresettable — it exists for quick demos, not production code.
Binding subsystem (extensible)#
The binding package exposes its singleton instances as package-level variables, making them both directly callable and overridable:
binding.JSON // BindingBody — application/json
binding.XML // BindingBody — application/xml
binding.Form // Binding — form / query
binding.Query // Binding — query string only
binding.YAML // BindingBody
binding.TOML // BindingBody
binding.ProtoBuf // BindingBody
binding.MsgPack // BindingBody
binding.BSON // BindingBody
binding.Header // Binding — HTTP headers
binding.Plain // BindingBody — text/plain
binding.Uri // BindingUri — URL path parameters
binding.Validator // StructValidator — replace to swap validation engineCustom bindings implement binding.Binding (2 methods) or binding.BindingBody (3 methods) and are passed directly to c.ShouldBindWith(obj, myBinding).
Render subsystem (extensible)#
Any type implementing render.Render can be passed to c.Render(code, myRenderer):
type Render interface {
Render(http.ResponseWriter) error
WriteContentType(w http.ResponseWriter)
}Built-in renders: JSON, IndentedJSON, SecureJSON, JsonpJSON, PureJSON, AsciiJSON, XML, HTML (debug/production variants), YAML, TOML, ProtoBuf, MsgPack, BSON, SSEvent, Reader, Data, String, Redirect, PDF.
API style#
Fluent chaining on registration: all route-registration methods return IRoutes, enabling:
engine.Use(Logger()).Use(Recovery()).GET("/ping", handler)Flat surface on Context: rather than sub-objects (c.Response.JSON(...), c.Request.BindJSON(...)), all functionality is directly on *Context. This is intentional — one receiver, maximum discoverability. The tradeoff is a large method set (~80+ methods on *Context).
No generics in the public API. All binding/rendering uses any. Typed Get* accessors exist for primitive types but the key/value store itself is map[any]any. This is a pre-generics design that has not been updated; callers who want type safety write wrapper functions.
Backward compatibility#
Gin follows SemVer at v1 (go.mod: module github.com/gin-gonic/gin). The project maintains strict backward compatibility within v1: new middleware constructors and new Context methods are added, existing signatures are not changed. The OptionFunc construction pattern gives the engine a non-breaking extension point for new configuration options.
The ginS package exists partly as a compatibility shim: older Gin tutorials used the global API before gin.Default() became the idiomatic entry point.