vodka

package module
v0.3.3 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2026 License: MIT Imports: 21 Imported by: 0

README

Vodka

Go Version License Status

__/\\\________/\\\_______/\\\\\_______/\\\\\\\\\\\\_____/\\\________/\\\_____/\\\\\\\\\____        
 _\/\\\_______\/\\\_____/\\\///\\\____\/\\\////////\\\__\/\\\_____/\\\//____/\\\\\\\\\\\\\__       
  _\//\\\______/\\\____/\\\/__\///\\\__\/\\\______\//\\\_\/\\\__/\\\//______/\\\/////////\\\_      
   __\//\\\____/\\\____/\\\______\//\\\_\/\\\_______\/\\\_\/\\\\\\//\\\_____\/\\\_______\/\\\_     
    ___\//\\\__/\\\____\/\\\_______\/\\\_\/\\\_______\/\\\_\/\\\//_\//\\\____\/\\\\\\\\\\\\\\\_    
     ____\//\\\/\\\_____\//\\\______/\\\__\/\\\_______\/\\\_\/\\\____\//\\\___\/\\\/////////\\\_   
      _____\//\\\\\_______\///\\\__/\\\____\/\\\_______/\\\__\/\\\_____\//\\\__\/\\\_______\/\\\_  
       ______\//\\\__________\///\\\\\/_____\/\\\\\\\\\\\\/___\/\\\______\//\\\_\/\\\_______\/\\\_ 
        _______\///_____________\/////_______\////////////_____\///________\///__\///________\///__

A modern Go web framework focused on developer experience, full-stack workflow, and rapid iteration.

Vodka is a lightweight and high-performance HTTP framework for Go that combines clean routing, middleware chaining, authentication utilities, validation support, and a powerful CLI for building modern full-stack applications.

Unlike traditional Go frameworks that focus only on request handling, Vodka heavily emphasizes developer experience and fast iteration.


Demo

Project Scaffolding

CLI Demo


Full Stack Workflow

Workflow


Table of Contents


Features

Feature Included
Radix Tree Routing
Middleware Chaining
Route Groups
JSON Binding
Request Validation
JWT Validation Helpers
Bearer Auth Middleware
Vite + React Scaffolding
SPA Serving
Panic Recovery Middleware
Logger Middleware
CORS Middleware
Context Storage
HTML Template Rendering

Why Vodka?

Vodka combines:

  • ⚡ Fast backend iteration
  • ⚛️ React + Vite integration
  • 🧩 Lightweight routing
  • 🔐 Authentication helpers
  • ✅ Validation support
  • 🚀 Developer-first workflow

without requiring heavy configuration or excessive boilerplate.


Prerequisites

Make sure the following tools are installed before using Vodka:

  • Go 1.24+
  • Node.js 20.19+ or newer
  • npm

Verify installation:

go version
node -v
npm -v

Installation

Install the Vodka CLI

go install github.com/DevanshuTripathi/vodka/cmd/vodka@latest

Make sure your Go bin directory is added to your system PATH.


Linux / macOS

export PATH=$PATH:$(go env GOPATH)/bin

Windows

Add the following directory to Environment Variables:

%USERPROFILE%\go\bin

Quick Start

Create a Full-Stack App

vodka create <project-name> [location] [--minimal]

Basic usage:

vodka create my-app

You can also specify a target directory to scaffold the project into:

vodka create my-app /path/to/parent-dir

The project will be created at <location>/<name> (e.g. /path/to/parent-dir/my-app). If no location is provided, the current directory is used.

vodka create my-app --minimal
vodka create my-app /path/to/dir --minimal

This generates:

  • A Go backend powered by Vodka
  • A React + Vite frontend
  • Preconfigured development workflow
  • SPA support for production deployments

Generated Project Structure

my-app/
├── controllers/
├── routes/
├── frontend/
├── main.go
├── go.mod
└── vodka.config.json

Install Frontend Dependencies

After scaffolding the project, install frontend dependencies manually:

cd my-app

cd frontend
npm install

cd ..

Start Development Mode

vodka run dev

This starts:

  • Vite frontend dev server
  • Vodka backend server
  • Concurrent frontend/backend workflow

Generated Backend Structure

Vodka organizes backend code into simple and clean layers.

backend/
├── controllers/
│   └── ping.go
├── routes/
│   └── routes.go
├── main.go
└── go.mod

controllers/

Contains request handlers and business logic.

func Pong(c *vodka.Context) {
	c.String(200, "Pong!")
}

routes/

Registers API routes.

app.GET("/ping", controllers.Pong)

main.go

Bootstraps the Vodka engine and middleware configuration.

app := vodka.DefaultRouter()

routes.Setup(app)

app.Run(":8080")

Minimal API Example

package main

import (
	"log"

	"github.com/DevanshuTripathi/vodka"
)

func main() {
	app := vodka.DefaultRouter()

	app.GET("/ping", func(c *vodka.Context) {
		c.JSON(200, vodka.M{
			"message": "pong!",
		})
	})

	if err := app.Run(":8080"); err != nil {
		log.Fatal(err)
	}
}

Test the API

curl http://localhost:8080/ping

Response:

{
  "message": "pong!"
}

Using Vodka for APIs

Create a Go Module

mkdir backend-app

cd backend-app

go mod init app

go get github.com/DevanshuTripathi/vodka

Run Backend Server

vodka

Vodka automatically:

  • Watches .go files
  • Rebuilds your backend
  • Restarts the server instantly

Core Concepts

Engine

vodka.Engine is the central router and application instance.

It uses a Radix Tree-based routing architecture for fast request matching and low overhead.

app := vodka.DefaultRouter()

Context

vodka.Context wraps Go's http.Request and http.ResponseWriter into a clean and ergonomic API.


JSON Response
c.JSON(200, vodka.M{
	"message": "hello",
})

Query Parameters
name := c.Query("name")

URL Parameters
id := c.Param("id")

Bind JSON
var user User
c.BindJSON(&user)

Error Handling
c.Error(400, errors.New("invalid request"))

Middleware

Vodka middleware is simply a vodka.HandlerFunc.

func(*vodka.Context)

Middlewares can:

  • Modify requests
  • Attach values to context
  • Authenticate users
  • Log requests
  • Recover from panics
  • Handle errors

Middlewares are registered using:

app.Use(...)

or:

group.Use(...)

How Middleware Works

Each incoming request is wrapped in a *vodka.Context and the framework builds a handler chain.

The chain includes:

  • Group middlewares
  • Route middlewares
  • Final route handler

c.Next() continues execution to the next middleware or handler.

If you omit c.Next(), the request chain stops immediately.


Custom Middleware Example

func RequestTimer() vodka.HandlerFunc {
	return func(c *vodka.Context) {
		start := time.Now()

		c.Next()

		latency := time.Since(start)

		log.Printf(
			"[RequestTimer] %s %s %v",
			c.Request.Method,
			c.Request.URL.Path,
			latency,
		)
	}
}

func main() {
	app := vodka.DefaultRouter()

	app.Use(
		vodka.Logger(),
		vodka.Recovery(),
		vodka.ErrorHandler(),
	)

	app.Use(RequestTimer())

	api := app.Group("/api", AdminOnly())

	api.GET("/dashboard", func(c *vodka.Context) {
		userRole, _ := c.Get("user_role")

		c.JSON(200, vodka.M{
			"role": userRole,
		})
	})
}

Request ID Middleware

Track requests across your logs using automatic request ID generation. Every request gets a unique ID that's automatically added to response headers and stored in the context.

app := vodka.DefaultRouter()

// Add request ID middleware — generates unique ID for each request
app.Use(mixers.RequestID())

app.GET("/api/users", func(c *vodka.Context) {
	requestID, _ := c.Get("request-id")
	log.Printf("[%v] Fetching users", requestID)
	c.JSON(200, vodka.M{"users": []string{"Alice", "Bob"}})
})

// Client receives: X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
Custom Header Name

Use a different header name if needed (context key is always "request-id"):

app.Use(mixers.RequestIDWithHeader("X-Correlation-ID"))

Template Rendering

Vodka supports Go's native html/template package for server-side HTML rendering.

Basic Usage

app := vodka.DefaultRouter()

// Load all templates from templates folder
app.LoadHTMLGlob("templates/*.html")

app.GET("/user", func(c *vodka.Context) {
    c.HTML(200, "user.html", vodka.M{
        "name": "John Doe",
        "email": "john@example.com",
    })
})

## Template Files

Create a templates/user.html file:

```html
<!DOCTYPE html>
<html>
<head>
    <title>User Profile</title>
</head>
<body>
    <h1>Hello, {{.name}}!</h1>
    <p>Email: {{.email}}</p>
</body>
</html>  ```

## Methods
LoadHTMLGlob(pattern string) error - Load templates using glob pattern

LoadHTMLFiles(files ...string) error - Load specific template files

c.HTML(code int, name string, data interface{}) - Render HTML template

Templates work seamlessly with Vodka's hot-reload in development mode.


# Validation

Vodka supports request validation using struct tags.

```go
type User struct {
	Email    string `validate:"required,email"`
	Password string `validate:"min=8"`
}

Authentication

Vodka includes built-in Bearer authentication middleware and JWT validation helpers.

You can also provide custom validation logic:

app.Use(vodka.BearerAuth(contextKey, func(token string) (any, bool) {
	return validateToken(token)
}))

Full-Stack SPA Support

Projects generated using vodka create come with SPA serving preconfigured.

app.ServeSPA("./frontend/dist")

If a route does not match an API endpoint, Vodka automatically serves the frontend application.

This enables seamless React Router support in production.


Performance

Vodka uses a Radix Tree router optimized for:

  • Fast route matching
  • Low memory overhead
  • Efficient middleware execution

Production Build

Build Frontend

cd frontend
npm run build

Build Backend

vodka

Philosophy

Vodka is designed around a few core ideas:

  • Fast development workflow
  • Minimal boilerplate
  • Strong developer experience
  • Clean APIs
  • Modern full-stack integration
  • Practical defaults

Roadmap

  • More middleware packages
  • Enhanced validation system
  • Improved benchmarking suite
  • Expanded CLI tooling
  • Testing utilities

Contributing

Contributions, issues, and feature requests are welcome.

If you find bugs or have suggestions, feel free to open an issue or submit a pull request.


License

MIT License

Documentation

Index

Constants

View Source
const (
	Reset  = "\033[0m"
	Red    = "\033[31m"
	Green  = "\033[32m"
	Yellow = "\033[33m"
	Blue   = "\033[34m"
	Cyan   = "\033[36m"
	Gray   = "\033[37m"
)

ANSI Color Escape Codes

Variables

This section is empty.

Functions

This section is empty.

Types

type CORSConfig added in v0.3.3

type CORSConfig struct {
	Origins []string
	MaxAge  int
}

CORSConfig holds configuration options for the CORS middleware

type Context

type Context struct {
	Writer  http.ResponseWriter // net/http response writer
	Request *http.Request       // net/http request
	Params  httprouter.Params   // URL Parameters for dynamic routing
	Keys    map[string]any      // Key-Value Store
	Errors  []*VodkaError       // Stores errors along the middleware chain
	// contains filtered or unexported fields
}

func (*Context) Abort added in v0.1.1

func (c *Context) Abort()

Abort http request

func (*Context) BindJSON

func (c *Context) BindJSON(obj any) error

BindJSON parses the Request Body

func (*Context) BindJSONReusable added in v0.3.3

func (c *Context) BindJSONReusable(obj any) error

func (*Context) ClearCookie added in v0.2.17

func (c *Context) ClearCookie(name string)

ClearCookie deletes a cookie by setting its MaxAge to -1.

func (*Context) ClientIP added in v0.2.17

func (c *Context) ClientIP() string

Helper to get actual client ip when XFF is involved. NOTE: SetTrustedProxies must be called on the engine before this method can parse X-Forwarded-For headers. Without it, ClientIP always returns RemoteAddr.

func (*Context) Cookie added in v0.2.17

func (c *Context) Cookie(name string) (string, error)

Cookie returns the value of the named cookie from the request. Returns an error if the cookie is not found.

func (*Context) Copy added in v0.2.17

func (c *Context) Copy() *Context

helper function to copy context for using it outisde the request lifecycle

func (*Context) DefaultQuery

func (c *Context) DefaultQuery(key string, defautlValue string) string

Default Query returns value if exists otherwise a default value

func (*Context) Error added in v0.2.10

func (c *Context) Error(statusCode int, err error)

Stores Errors in the context to be handled by ErrorHandler Middleware

func (*Context) FormFile added in v0.2.8

func (c *Context) FormFile(name string) (*multipart.FileHeader, error)

Retrieves a single file from multipart form

func (*Context) FormValue added in v0.2.8

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

Retrieves text value from a miltipart form

func (*Context) Get added in v0.2.7

func (c *Context) Get(key string) (value any, exists bool)

Get value from a key after a previous middleware assigned it

func (*Context) HTML added in v0.3.2

func (c *Context) HTML(code int, name string, data interface{})

HTML renders an HTML template with the given status code and data

func (*Context) IP added in v0.2.13

func (c *Context) IP() string

Helper to get request IP

func (*Context) Initialize added in v0.2.17

func (c *Context) Initialize(w http.ResponseWriter, r *http.Request, p httprouter.Params, handlers []HandlerFunc, e *Engine)

helper to initialize Context

func (*Context) JSON

func (c *Context) JSON(statusCode int, obj any)

Encode Response to JSON

func (*Context) Next

func (c *Context) Next()

Step By Step execution of middlewares doesnt handle abort

func (*Context) NoContent added in v0.3.3

func (c *Context) NoContent()

func (*Context) Param

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

Get Param Value

func (*Context) ParamBool added in v0.2.16

func (c *Context) ParamBool(key string) (bool, error)

ParamBool returns URL param as bool or an error

func (*Context) ParamInt added in v0.2.16

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

ParamInt returns URL param as int or an error

func (*Context) Query

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

Find Query Values

func (*Context) QueryBool added in v0.2.16

func (c *Context) QueryBool(key string) (bool, error)

QueryBool returns query param as bool or an error

func (*Context) QueryInt added in v0.2.16

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

QueryInt returns query param as int or an error

func (*Context) Redirect added in v0.3.3

func (c *Context) Redirect(statusCode int, location string)

func (*Context) Reset added in v0.2.17

func (c *Context) Reset()

helper function to reset Context

func (*Context) SaveUploadedFile added in v0.2.8

func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error

Saves Uploaded File to destination on disk

func (*Context) Set added in v0.2.7

func (c *Context) Set(key string, value any)

Set Values into Keys into the context to be used later by another middleware

func (*Context) SetCookie added in v0.2.17

func (c *Context) SetCookie(name, value string, maxAge int)

SetCookie writes a cookie to the response. maxAge is in seconds. Use 0 for session cookie, negative to delete.

func (*Context) Status added in v0.3.3

func (c *Context) Status(code int)

func (*Context) String

func (c *Context) String(statusCode int, text string)

Basic String Response

func (*Context) XML added in v0.3.3

func (c *Context) XML(statusCode int, obj any)

type Engine

type Engine struct {
	WSConfig *WSConfig

	*RouterGroup
	// contains filtered or unexported fields
}

httprouter wrapper

func DefaultRouter added in v0.1.1

func DefaultRouter() *Engine

func NewRouter added in v0.1.1

func NewRouter() *Engine

creates a new router

func (*Engine) AllowWSOrigins added in v0.2.16

func (e *Engine) AllowWSOrigins(origins []string)

AllowWSOrigins whitelists the given origins for WebSocket upgrade requests. Call this before registering WS routes.

app.AllowWSOrigins([]string{"https://userapp.com", "https://admin.com"})

func (*Engine) LoadHTMLFiles added in v0.3.2

func (e *Engine) LoadHTMLFiles(files ...string) error

LoadHTMLFiles parses and caches specific template files

func (*Engine) LoadHTMLGlob added in v0.3.2

func (e *Engine) LoadHTMLGlob(pattern string) error

LoadHTMLGlob parses and caches templates from a glob pattern

func (*Engine) Run

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

Runs the http server

func (*Engine) ServeHTTP added in v0.2.5

func (e *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP intercepts every request before it hits the router

func (*Engine) ServeSPA added in v0.1.3

func (e *Engine) ServeSPA(root string)

SPA fallback

func (*Engine) SetTrustedProxies added in v0.2.17

func (e *Engine) SetTrustedProxies(proxies []string) error

Sets trusted Proxies

type HandlerFunc

type HandlerFunc func(*Context) // Handler Function with Context wrapping

func AllowCORS added in v0.2.1

func AllowCORS(origins []string, config ...CORSConfig) HandlerFunc

func ErrorHandler added in v0.2.10

func ErrorHandler() HandlerFunc

Error Handler Middleware

func Logger

func Logger() HandlerFunc

func Recovery added in v0.1.1

func Recovery() HandlerFunc

type M

type M map[string]any // Shortcut map

type RouterGroup added in v0.1.1

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

func (*RouterGroup) DELETE added in v0.1.1

func (rg *RouterGroup) DELETE(path string, handler HandlerFunc)

func (*RouterGroup) GET added in v0.1.1

func (rg *RouterGroup) GET(path string, handler HandlerFunc)

func (*RouterGroup) Group added in v0.1.1

func (rg *RouterGroup) Group(prefix string, middlewares ...HandlerFunc) *RouterGroup

func (*RouterGroup) HEAD added in v0.3.0

func (rg *RouterGroup) HEAD(path string, handler HandlerFunc)

func (*RouterGroup) PATCH added in v0.3.0

func (rg *RouterGroup) PATCH(path string, handler HandlerFunc)

func (*RouterGroup) POST added in v0.1.1

func (rg *RouterGroup) POST(path string, handler HandlerFunc)

func (*RouterGroup) PUT added in v0.1.1

func (rg *RouterGroup) PUT(path string, handler HandlerFunc)

func (*RouterGroup) SSE added in v0.2.16

func (rg *RouterGroup) SSE(relativePath string, handler SSEHandlerFunc)

SSE registers a Server-Sent Events handler at the given path. The response is kept open and events are pushed to the client until it disconnects. Group middlewares run before the SSE stream is opened.

func (*RouterGroup) Static added in v0.1.2

func (rg *RouterGroup) Static(relativePath string, root string)

Serve Static files

func (*RouterGroup) Use added in v0.1.1

func (rg *RouterGroup) Use(middlewares ...HandlerFunc)

func (*RouterGroup) WS added in v0.2.16

func (rg *RouterGroup) WS(relativePath string, handler WSHandlerFunc)

WS registers a WebSocket handler at the given path. Group middlewares (auth, rate limiting, etc.) run during the HTTP upgrade phase. If any middleware aborts the request, the upgrade is cancelled.

type SSEContext added in v0.2.16

type SSEContext struct {
	Writer http.ResponseWriter

	Keys    map[string]any
	Params  httprouter.Params
	Request *http.Request
	// contains filtered or unexported fields
}

SSEContext wraps an active SSE connection with framework utilities. Use Send() to push events and Done() to detect client disconnection.

func (*SSEContext) Done added in v0.2.16

func (sc *SSEContext) Done() <-chan struct{}

Done returns a channel that is closed when the client disconnects. Use this to stop your event loop cleanly.

for {
    select {
    case <-c.Done():
        return
    default:
        c.Send("ping", vodka.M{"ts": time.Now()})
        time.Sleep(time.Second)
    }
}

func (*SSEContext) Get added in v0.2.16

func (sc *SSEContext) Get(key string) (value any, exists bool)

Get retrieves a value previously stored via Set.

func (*SSEContext) IP added in v0.2.16

func (sc *SSEContext) IP() string

IP returns the remote address of the client.

func (*SSEContext) Param added in v0.2.16

func (sc *SSEContext) Param(key string) string

Param returns a URL path parameter by name.

func (*SSEContext) Query added in v0.2.16

func (sc *SSEContext) Query(key string) string

Query returns a URL query parameter by name.

func (*SSEContext) Send added in v0.2.16

func (sc *SSEContext) Send(event string, data any) error

Send pushes a named event with JSON-encoded data to the client. Returns an error if the connection is no longer writable.

c.Send("update", vodka.M{"value": 42})

func (*SSEContext) SendComment added in v0.2.16

func (sc *SSEContext) SendComment(comment string) error

SendComment writes an SSE comment line, useful as a keep-alive ping.

func (*SSEContext) SendData added in v0.2.16

func (sc *SSEContext) SendData(data any) error

SendData pushes data without a named event (browsers receive it as a "message" event).

func (*SSEContext) Set added in v0.2.16

func (sc *SSEContext) Set(key string, value any)

Set stores a value in the context by key.

type SSEHandlerFunc added in v0.2.16

type SSEHandlerFunc func(*SSEContext)

SSEHandlerFunc is the handler signature for Server-Sent Events connections.

type VodkaError added in v0.2.10

type VodkaError struct {
	Err    error
	Status int
}

Custom error type

func (*VodkaError) Error added in v0.2.10

func (v *VodkaError) Error() string

return string error

type WSConfig added in v0.2.16

type WSConfig struct {
	ReadBufferSize   int
	WriteBufferSize  int
	HandshakeTimeout time.Duration
	// CheckOrigin returns true to allow the connection. Defaults to allowing all origins.
	CheckOrigin func(r *http.Request) bool
}

WSConfig holds configuration for the WebSocket upgrader.

func DefaultWSConfig added in v0.2.16

func DefaultWSConfig() *WSConfig

DefaultWSConfig returns a WSConfig with sensible defaults. By default only same-origin requests are allowed. Use engine.AllowWSOrigins() to permit others.

type WSContext added in v0.2.16

type WSContext struct {
	Conn    *websocket.Conn
	Keys    map[string]any
	Params  httprouter.Params
	Request *http.Request
}

WSContext wraps a live WebSocket connection with framework utilities. URL params, query values, and keys set by HTTP middlewares are all accessible here.

func (*WSContext) Close added in v0.2.16

func (wc *WSContext) Close() error

Close sends a normal closure message and closes the connection gracefully.

func (*WSContext) Get added in v0.2.16

func (wc *WSContext) Get(key string) (value any, exists bool)

Get retrieves a value previously stored via Set.

func (*WSContext) IP added in v0.2.16

func (wc *WSContext) IP() string

IP returns the remote address of the client.

func (*WSContext) Param added in v0.2.16

func (wc *WSContext) Param(key string) string

Param returns a URL path parameter by name (e.g. /ws/:room → wc.Param("room")).

func (*WSContext) Query added in v0.2.16

func (wc *WSContext) Query(key string) string

Query returns a URL query parameter by name.

func (*WSContext) ReadJSON added in v0.2.16

func (wc *WSContext) ReadJSON(v any) error

ReadJSON reads the next message and decodes it as JSON into v.

func (*WSContext) ReadMessage added in v0.2.16

func (wc *WSContext) ReadMessage() (messageType int, p []byte, err error)

ReadMessage reads the next message from the connection. messageType is websocket.TextMessage or websocket.BinaryMessage.

func (*WSContext) Set added in v0.2.16

func (wc *WSContext) Set(key string, value any)

Set stores a value in the context by key, shared across the connection lifecycle.

func (*WSContext) WriteJSON added in v0.2.16

func (wc *WSContext) WriteJSON(v any) error

WriteJSON encodes v as JSON and sends it as a text message.

func (*WSContext) WriteMessage added in v0.2.16

func (wc *WSContext) WriteMessage(messageType int, data []byte) error

WriteMessage writes a message to the connection.

type WSHandlerFunc added in v0.2.16

type WSHandlerFunc func(*WSContext)

WSHandlerFunc is the handler signature for WebSocket connections.

Directories

Path Synopsis
cmd
vodka command
examples
html-templates command
sse command
websocket command

Jump to

Keyboard shortcuts

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