Help us shape the future of Go! Take the 2026 Go Developer Survey

goichi

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 12, 2026 License: MIT Imports: 27 Imported by: 0

README

Goichi

Go Reference Go Report Card

Goichi is a high-performance, modular web API framework for Go with multi-protocol support. A single application can serve REST, WebSocket, GraphQL, gRPC/ConnectRPC, MQTT and MCP — through one unified middleware and authentication model.

Status: v0.x. The API may still change between minor versions.

Features

  • One app, many protocols — REST, WebSocket, GraphQL, gRPC, ConnectRPC, MQTT and MCP, optionally multiplexed onto a single port.
  • Unified middleware — the same middleware chain (auth, logging, rate limiting, recovery, CORS, …) applies across protocols.
  • Unified JWT auth — configure a signing secret once and every protocol enforces it. Built on github.com/golang-jwt/jwt/v5, pinned to HMAC and requiring an expiry.
  • Secure by default — panic recovery and security headers are installed for you, CORS allows no origins until you configure it, and errors never leak internals to clients.
  • Correct HTTP by default — automatic OPTIONS (so CORS preflight works without extra routes), 405 with an Allow header, and HEAD served from the matching GET.
  • Built-in API docs — generate OpenAPI documentation from your routes.

Install

go get github.com/goichi-dev/goichi

Requires Go 1.25 or later.

Quick Start

package main

import "github.com/goichi-dev/goichi"

func main() {
	app := goichi.New(goichi.Config{})

	app.GET("/hello/:name", func(c *goichi.Context) error {
		return c.JSON(map[string]string{
			"message": "Hello, " + c.Param("name"),
		})
	})

	app.Listen(":3000")
}
go run .
# GET http://localhost:3000/hello/world -> {"message":"Hello, world"}

Routing

Paths support :name parameters and a trailing *rest catch-all. Static segments take priority over parameters, which take priority over the catch-all.

By default a trailing slash is ignored and literal segments match without regard to ASCII case — /Users/42 reaches a /users/:id route. Parameter values always keep their original casing. Both behaviours are configurable:

app := goichi.New(goichi.Config{
	Routing: goichi.RoutingConfig{StrictSlash: true, CaseSensitive: true},
})

Middleware

Middleware is a func(goichi.Handler) goichi.Handler. Register it globally, per group, or per route:

app.Use(middleware.Logger())

api := app.Group("/api", middleware.RateLimit(100))
api.GET("/users", listUsers, middleware.Cache(30*time.Second))

The route table is compiled once before the first request, so Use still applies to routes that were declared before it.

Authentication

One secret protects every protocol:

app := goichi.New(goichi.Config{
	JWT: middleware.JWTConfig{Secret: os.Getenv("JWT_SECRET")},
})

app.GET("/public", handler).NoAuth() // opt out

The generated docs, /favicon.ico and the health endpoint are exempt already, so enabling auth never locks you out of your own API reference.

Multi-protocol example

Runnable examples — one per protocol, plus a server that starts every protocol from a single process — live in goichi-dev/goichi-examples.

Documentation

Contributing

Bug reports and pull requests are welcome. See CONTRIBUTING.md for the build and review process, and SECURITY.md for reporting a vulnerability privately.

License

MIT — see LICENSE.

Documentation

Overview

Package goichi is a multi-protocol web API framework for Go.

A single App can serve REST, WebSocket, GraphQL, gRPC, ConnectRPC, MQTT and MCP, optionally multiplexed onto one TCP port, behind one middleware chain and one JWT configuration.

Getting started

app := goichi.New(goichi.Config{})

app.GET("/hello/:name", func(c *goichi.Context) error {
	return c.JSON(map[string]string{"message": "Hello, " + c.Param("name")})
})

app.Listen(":3000")

Routing

Paths may contain ":name" parameters and a trailing "*rest" catch-all. Static segments win over parameters, which win over the catch-all. By default the router ignores a trailing slash and matches literal segments without regard to ASCII case; see RoutingConfig. Parameter values always keep their original casing.

Requests to a known path with an unregistered method receive 405 together with an Allow header, and OPTIONS is answered automatically, so CORS preflight works without declaring OPTIONS routes.

Middleware

Middleware is a func(Handler) Handler. Register it globally with App.Use, per group, or per route. The route table is compiled once before the first request, so Use may be called after the routes it should wrap have been declared.

middleware.Recover and middleware.SecurityHeaders are installed by default: fasthttp does not recover panics on its own, and an escaping panic would take down the process rather than the request.

Authentication

Setting Config.JWT.Secret enables the same HS256 verification for every protocol at once. Individual routes opt out with Route.NoAuth; the built-in docs, favicon and health endpoints already do.

Protocols

Protocol servers are registered with App.RegisterProtocol and started with the app. With Config.Server.EnablePortMultiplexing the HTTP-based protocols share the main port. MQTT and MCP always listen on their own port: MCP speaks JSON-RPC over raw TCP and is never mounted on the HTTP router.

Index

Constants

View Source
const (
	// 2xx Success
	StatusOK                   = core.StatusOK
	StatusCreated              = core.StatusCreated
	StatusAccepted             = core.StatusAccepted
	StatusNonAuthoritativeInfo = core.StatusNonAuthoritativeInfo
	StatusNoContent            = core.StatusNoContent
	StatusResetContent         = core.StatusResetContent
	StatusPartialContent       = core.StatusPartialContent

	// 3xx Redirection
	StatusMultipleChoices   = core.StatusMultipleChoices
	StatusMovedPermanently  = core.StatusMovedPermanently
	StatusFound             = core.StatusFound
	StatusSeeOther          = core.StatusSeeOther
	StatusNotModified       = core.StatusNotModified
	StatusTemporaryRedirect = core.StatusTemporaryRedirect
	StatusPermanentRedirect = core.StatusPermanentRedirect

	// 4xx Client errors
	StatusBadRequest                   = core.StatusBadRequest
	StatusUnauthorized                 = core.StatusUnauthorized
	StatusPaymentRequired              = core.StatusPaymentRequired
	StatusForbidden                    = core.StatusForbidden
	StatusNotFound                     = core.StatusNotFound
	StatusMethodNotAllowed             = core.StatusMethodNotAllowed
	StatusNotAcceptable                = core.StatusNotAcceptable
	StatusProxyAuthRequired            = core.StatusProxyAuthRequired
	StatusRequestTimeout               = core.StatusRequestTimeout
	StatusConflict                     = core.StatusConflict
	StatusGone                         = core.StatusGone
	StatusLengthRequired               = core.StatusLengthRequired
	StatusPreconditionFailed           = core.StatusPreconditionFailed
	StatusRequestEntityTooLarge        = core.StatusRequestEntityTooLarge
	StatusRequestURITooLong            = core.StatusRequestURITooLong
	StatusUnsupportedMediaType         = core.StatusUnsupportedMediaType
	StatusRequestedRangeNotSatisfiable = core.StatusRequestedRangeNotSatisfiable
	StatusExpectationFailed            = core.StatusExpectationFailed
	StatusTeapot                       = core.StatusTeapot
	StatusUnprocessableEntity          = core.StatusUnprocessableEntity
	StatusLocked                       = core.StatusLocked
	StatusFailedDependency             = core.StatusFailedDependency
	StatusUpgradeRequired              = core.StatusUpgradeRequired
	StatusPreconditionRequired         = core.StatusPreconditionRequired
	StatusTooManyRequests              = core.StatusTooManyRequests
	StatusHeaderFieldsTooLarge         = core.StatusHeaderFieldsTooLarge
	StatusUnavailableForLegalReasons   = core.StatusUnavailableForLegalReasons

	// 5xx Server errors
	StatusInternalServerError           = core.StatusInternalServerError
	StatusNotImplemented                = core.StatusNotImplemented
	StatusBadGateway                    = core.StatusBadGateway
	StatusServiceUnavailable            = core.StatusServiceUnavailable
	StatusGatewayTimeout                = core.StatusGatewayTimeout
	StatusHTTPVersionNotSupported       = core.StatusHTTPVersionNotSupported
	StatusVariantAlsoNegotiates         = core.StatusVariantAlsoNegotiates
	StatusInsufficientStorage           = core.StatusInsufficientStorage
	StatusLoopDetected                  = core.StatusLoopDetected
	StatusNotExtended                   = core.StatusNotExtended
	StatusNetworkAuthenticationRequired = core.StatusNetworkAuthenticationRequired
)

HTTP status codes, re-exported from the core package so applications only need to import goichi.

Variables

This section is empty.

Functions

func B64Encode

func B64Encode(s string) string

B64Encode returns the standard base64 encoding of s.

func ErrBadRequest

func ErrBadRequest(c *core.Context, msg string) error

func ErrForbidden

func ErrForbidden(c *core.Context) error

func ErrInternal

func ErrInternal(c *core.Context) error

func ErrNotFound

func ErrNotFound(c *core.Context, entity string) error

func ErrUnauthorized

func ErrUnauthorized(c *core.Context) error

func ErrValidation

func ErrValidation(c *core.Context, ve *core.ValidationError) error

func Send

func Send(c *core.Context, data any) error

func SendCreated

func SendCreated(c *core.Context, data any) error

func SendPage

func SendPage(c *core.Context, items any, page, perPage, total int) error

Types

type App

type App struct {
	Router *Router
	Config Config

	Registry *protocol.ProtocolRegistry
	// contains filtered or unexported fields
}

App is a configured application: a router, a set of protocol servers and the middleware shared between them. Create one with New.

func New

func New(config Config) *App

New returns an App configured by config, with panic recovery and security headers already installed. When config.JWT.Secret is set, unified JWT auth is enabled for every protocol.

func (*App) ANY

func (a *App) ANY(path string, h Handler, m ...Middleware) Routes

ANY registers the same handler for every common HTTP method.

func (*App) AddDocs

func (a *App) AddDocs(config DocsConfig)

AddDocs registers an additional documentation page, letting one app expose several filtered views of its API.

func (*App) DELETE

func (a *App) DELETE(path string, h Handler, m ...Middleware) *Route

DELETE registers a handler for DELETE requests to path.

func (*App) EnableHealthCheck

func (a *App) EnableHealthCheck(path string)

EnableHealthCheck registers a plain-text liveness endpoint. It is exempt from unified JWT auth so probes do not need a token.

func (*App) GET

func (a *App) GET(path string, h Handler, m ...Middleware) *Route

GET registers a handler for GET requests to path.

func (*App) GetProtocols

func (a *App) GetProtocols() *protocol.ProtocolRegistry

func (*App) GetRoutes

func (a *App) GetRoutes() []*RouteInfo

GetRoutes returns metadata for every registered route.

func (*App) Group

func (a *App) Group(prefix string, m ...Middleware) *Group

Group returns a route group sharing a path prefix and middleware.

func (*App) IsMaster

func (a *App) IsMaster() bool

IsMaster reports whether this is the parent process, which is always true unless multiprocess mode spawned it as a child.

func (*App) Listen

func (a *App) Listen(addr string) error

Listen binds addr and serves every registered protocol until the process receives SIGINT or SIGTERM.

func (*App) ListenGraceful

func (a *App) ListenGraceful(addr string) error

ListenGraceful binds addr like Listen, and additionally supports the multiprocess model configured by ServerConfig.Multiprocess.

func (*App) OnShutdown

func (a *App) OnShutdown(f ...func())

OnShutdown registers functions to run after the server stops accepting connections.

func (*App) PATCH

func (a *App) PATCH(path string, h Handler, m ...Middleware) *Route

PATCH registers a handler for PATCH requests to path.

func (*App) POST

func (a *App) POST(path string, h Handler, m ...Middleware) *Route

POST registers a handler for POST requests to path.

func (*App) PUT

func (a *App) PUT(path string, h Handler, m ...Middleware) *Route

PUT registers a handler for PUT requests to path.

func (*App) RegisterProtocol

func (a *App) RegisterProtocol(handler protocol.ProtocolHandler)

RegisterProtocol adds a protocol server to the app. It inherits the unified auth configuration and the middleware registered with UseProtocol.

func (*App) SetErrorHandler

func (a *App) SetErrorHandler(handler core.ErrorHandler)

SetErrorHandler replaces the default handler for errors returned by routes.

func (*App) SetJWTAuth

func (a *App) SetJWTAuth(cfg middleware.JWTConfig)

SetJWTAuth installs one JWT configuration for every protocol. Routes marked with Route.NoAuth are exempt; so are the built-in docs, favicon and health endpoints.

func (*App) StartAllProtocols

func (a *App) StartAllProtocols(ctx context.Context) error

func (*App) StartProtocols

func (a *App) StartProtocols(ctx context.Context, names ...string) error

func (*App) StopAllProtocols

func (a *App) StopAllProtocols(ctx context.Context) error

func (*App) Use

func (a *App) Use(m ...Middleware)

Use registers middleware for every route, including routes declared earlier.

func (*App) UseAll

func (a *App) UseAll(m ...Middleware)

UseAll registers middleware for the router and for every protocol server.

func (*App) UseGRPCStream

func (a *App) UseGRPCStream(i ...grpc.StreamServerInterceptor)

func (*App) UseGRPCUnary

func (a *App) UseGRPCUnary(i ...grpc.UnaryServerInterceptor)

func (*App) UseProtocol

func (a *App) UseProtocol(m ...ProtocolFastHTTPMiddleware)

func (*App) UseUnified

func (a *App) UseUnified(m ...UnifiedMiddleware)

func (*App) ValidateConfig

func (a *App) ValidateConfig() error

ValidateConfig checks the application configuration for required fields and potential misconfigurations (fail-fast).

type Config

type Config struct {
	Server  ServerConfig
	Routing RoutingConfig
	Docs    DocsConfig
	JWT     middleware.JWTConfig
	// Security is the default security scheme advertised in generated docs.
	Security openapi.SecurityScheme
}

Config is the application configuration passed to New.

type Context

type Context = core.Context

type DocsConfig

type DocsConfig struct {
	Enable      bool
	Path        string
	Title       string
	Desc        string
	PageTitle   string
	DarkMode    bool
	ScalarJSURL string
	Security    openapi.SecurityScheme
	Filter      func(*RouteInfo) bool
}

DocsConfig describes one generated OpenAPI reference page.

type Group

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

func (*Group) ANY

func (g *Group) ANY(path string, h Handler, m ...Middleware) Routes

func (*Group) DELETE

func (g *Group) DELETE(path string, h Handler, m ...Middleware) *Route

func (*Group) GET

func (g *Group) GET(path string, h Handler, m ...Middleware) *Route

func (*Group) Group

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

Group returns a nested group whose prefix and middleware extend this one.

func (*Group) PATCH

func (g *Group) PATCH(path string, h Handler, m ...Middleware) *Route

func (*Group) POST

func (g *Group) POST(path string, h Handler, m ...Middleware) *Route

func (*Group) PUT

func (g *Group) PUT(path string, h Handler, m ...Middleware) *Route

func (*Group) Static

func (g *Group) Static(prefix, root string)

type Handler

type Handler = core.Handler

type Middleware

type Middleware = core.Middleware

type Pagination

type Pagination = core.Pagination

type ProtocolFastHTTPMiddleware

type ProtocolFastHTTPMiddleware func(next fasthttp.RequestHandler) fasthttp.RequestHandler

func MiddlewareAsProtocol

func MiddlewareAsProtocol(m Middleware) ProtocolFastHTTPMiddleware

type Route

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

func (*Route) ContentType

func (r *Route) ContentType(ct string) *Route

func (*Route) HideDoc

func (r *Route) HideDoc() *Route

func (*Route) NoAuth

func (r *Route) NoAuth() *Route

func (*Route) RequestModel

func (r *Route) RequestModel(model any) *Route

func (*Route) ResponseModel

func (r *Route) ResponseModel(model any) *Route

func (*Route) Summary

func (r *Route) Summary(s string) *Route

func (*Route) Tags

func (r *Route) Tags(tags ...string) *Route

type RouteInfo

type RouteInfo struct {
	Method        string
	Path          string
	Summary       string
	Tags          []string
	ResponseModel any
	RequestModel  any
	NoAuth        bool
	HideDoc       bool
	ContentType   string
}

RouteInfo is the metadata describing a single registered route.

type RouteOption

type RouteOption func(*RouteInfo)

func WithRequest

func WithRequest(model any) RouteOption

func WithResponse

func WithResponse(model any) RouteOption

func WithSummary

func WithSummary(s string) RouteOption

func WithTags

func WithTags(tags ...string) RouteOption

type Router

type Router struct {

	// Routes describes every registered route. It backs the generated OpenAPI
	// document and is safe to read after registration.
	Routes []*RouteInfo

	// ErrorHandler, when set, receives any error returned by a handler.
	ErrorHandler core.ErrorHandler

	// StrictSlash distinguishes "/users" from "/users/" when true. When false
	// (the default) a trailing slash is ignored.
	StrictSlash bool

	// CaseSensitive matches literal path segments exactly when true. When false
	// (the default) "/Users" also matches a "/users" route. Parameter values
	// always keep their original casing.
	CaseSensitive bool
	// contains filtered or unexported fields
}

Router matches incoming requests against a radix tree per HTTP method and invokes the registered handler.

Handlers are not composed with their middleware at registration time. The whole table is compiled once, on the first request or on an explicit Build call, so that middleware registered with Use after a route was declared still applies to it.

func NewRouter

func NewRouter(strictSlash, caseSensitive bool) *Router

NewRouter returns a Router. See Router.StrictSlash and Router.CaseSensitive for the meaning of the two flags.

func (*Router) ANY

func (r *Router) ANY(path string, h Handler, m ...Middleware) Routes

ANY registers the same handler for every common HTTP method.

func (*Router) Build

func (r *Router) Build()

Build compiles the route table. It is called automatically before the first request; calling it earlier surfaces registration problems at startup.

func (*Router) DELETE

func (r *Router) DELETE(path string, h Handler, m ...Middleware) *Route

DELETE registers a handler for DELETE requests to path.

func (*Router) EnableDocs

func (r *Router) EnableDocs(path string, htmlContent string)

EnableDocs serves a static HTML page at path.

func (*Router) GET

func (r *Router) GET(path string, h Handler, m ...Middleware) *Route

GET registers a handler for GET requests to path.

func (*Router) HandleRequest

func (r *Router) HandleRequest(ctx *fasthttp.RequestCtx)

HandleRequest is the fasthttp entry point for the router.

func (*Router) PATCH

func (r *Router) PATCH(path string, h Handler, m ...Middleware) *Route

PATCH registers a handler for PATCH requests to path.

func (*Router) POST

func (r *Router) POST(path string, h Handler, m ...Middleware) *Route

POST registers a handler for POST requests to path.

func (*Router) PUT

func (r *Router) PUT(path string, h Handler, m ...Middleware) *Route

PUT registers a handler for PUT requests to path.

func (*Router) Static

func (r *Router) Static(prefix, root string)

Static serves the files under root at the given URL prefix.

func (*Router) Use

func (r *Router) Use(m ...Middleware)

Use registers global middleware. Unlike most routers, Use may be called after routes have been declared; the middleware still applies to them.

type Routes

type Routes []*Route

func (Routes) ContentType

func (rs Routes) ContentType(ct string) Routes

func (Routes) HideDoc

func (rs Routes) HideDoc() Routes

func (Routes) NoAuth

func (rs Routes) NoAuth() Routes

func (Routes) RequestModel

func (rs Routes) RequestModel(model any) Routes

func (Routes) ResponseModel

func (rs Routes) ResponseModel(model any) Routes

func (Routes) Summary

func (rs Routes) Summary(s string) Routes

func (Routes) Tags

func (rs Routes) Tags(tags ...string) Routes

type RoutingConfig

type RoutingConfig struct {
	// StrictSlash treats "/users" and "/users/" as different routes.
	StrictSlash bool

	// CaseSensitive matches literal path segments exactly. When false (the
	// default) "/Users" also reaches a "/users" route; parameter values keep
	// their original casing either way.
	CaseSensitive bool
}

RoutingConfig tunes how request paths are matched.

type ServerConfig

type ServerConfig struct {
	AppName                string
	Multiprocess           bool
	NumChildren            int
	ShowStartup            *bool
	StartupBanner          string
	EnablePortMultiplexing bool
	ReadTimeout            time.Duration
	WriteTimeout           time.Duration
	IdleTimeout            time.Duration
	MaxRequestBodySize     int

	// TLSCertFile and TLSKeyFile, when both set, serve the main HTTP listener
	// over TLS (https). Leave empty when TLS is terminated upstream.
	TLSCertFile string
	TLSKeyFile  string
}

ServerConfig controls the HTTP listener and process model.

func (*ServerConfig) SetDefaults

func (c *ServerConfig) SetDefaults()

SetDefaults fills in the timeouts, body limit and application name that were left at their zero value.

func (*ServerConfig) TLSEnabled

func (c *ServerConfig) TLSEnabled() bool

TLSEnabled reports whether both a certificate and key were configured for the main HTTP listener.

type UnifiedMiddleware

type UnifiedMiddleware interface {
	ToHTTP() ProtocolFastHTTPMiddleware
	ToGRPCUnary() grpc.UnaryServerInterceptor
	ToGRPCStream() grpc.StreamServerInterceptor
}

UnifiedMiddleware defines a middleware that can be applied to both HTTP and gRPC protocols.

type ValidationError

type ValidationError = core.ValidationError

Directories

Path Synopsis
mcp

Jump to

Keyboard shortcuts

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