ratelimit

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 8 Imported by: 0

README

togo

togo-framework/ratelimit

marketplace pkg.go.dev MIT

Request rate limiting & throttling for togo — token-bucket, per key, with standard headers.

Install

togo install togo-framework/ratelimit

A token-bucket limiter: each key (IP, user, route, or anything you choose) gets a bucket of Limit tokens that refills continuously over Window. A request consumes one token; when empty the request is denied with a Retry-After hint and a 429. Use it as HTTP middleware or call Allow directly.

Usage

As middleware

import (
	"time"
	"github.com/togo-framework/ratelimit"
)

s, _ := ratelimit.FromKernel(k)

// 60 requests/minute per client IP
api := s.Middleware(ratelimit.Rate("api", 60, time.Minute), nil)
r.With(api).Get("/things", listThings)

// 5 login attempts / 15 min, keyed by submitted email
login := s.Middleware(ratelimit.Rate("login", 5, 15*time.Minute), func(req *http.Request) string {
	return req.FormValue("email")
})
r.With(login).Post("/login", doLogin)

Responses carry the standard headers — X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset — and a denied request gets 429 Too Many Requests + Retry-After.

Direct check

allowed, retryAfter := s.Allow(ctx, userID, ratelimit.Rate("export", 10, time.Hour))
if !allowed {
	return fmt.Errorf("rate limited, retry in %s", retryAfter)
}

Key strategies

ratelimit.ClientIP (default, honors X-Forwarded-For), or any KeyFunc(*http.Request) string — key by user id, API key, route, tenant, etc.

Configuration

No required env. The default store is in-memory (per instance). For multi-instance deployments implement the small Store interface (one method, Take) backed by Redis via togo install togo-framework/cache-redis, and attach it with s.WithStore(myStore).


Premium sponsors

ID8 Media  ·  One Studio

Support togo — become a sponsor.

Documentation

Overview

Package ratelimit provides request rate limiting / throttling for togo apps.

It uses a token-bucket limiter: each key (an IP, user, route, or anything you choose) gets a bucket of Limit tokens that refills continuously over Window. A request consumes one token; when the bucket is empty the request is denied with a Retry-After hint. Use it as HTTP middleware or call Allow directly.

s, _ := ratelimit.FromKernel(k)
api := s.Middleware(ratelimit.Rate("api", 60, time.Minute), nil) // 60/min per IP
r.With(api).Get("/things", handler)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ClientIP

func ClientIP(r *http.Request) string

ClientIP returns the best-effort client IP (honoring X-Forwarded-For).

Types

type KeyFunc

type KeyFunc func(r *http.Request) string

KeyFunc extracts the rate-limit key from a request (default: client IP).

type Policy

type Policy struct {
	Name   string        `json:"name"`
	Limit  int           `json:"limit"`
	Window time.Duration `json:"window"`
}

Policy is a rate limit: at most Limit requests per Window (also the burst).

func Rate

func Rate(name string, limit int, window time.Duration) Policy

Rate builds a named policy: limit requests per window.

type Service

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

Service is the rate-limit runtime stored on the kernel (k.Get("ratelimit")).

func FromKernel

func FromKernel(k *togo.Kernel) (*Service, bool)

FromKernel returns the rate-limit Service registered on the kernel.

func New

func New() *Service

New builds a Service with the in-memory store.

func (*Service) Allow

func (s *Service) Allow(_ context.Context, key string, p Policy) (allowed bool, retryAfter time.Duration)

Allow reports whether a request under key is permitted by policy p. When denied it returns the duration to wait before retrying.

func (*Service) Define

func (s *Service) Define(p Policy)

Define registers a named policy so it can be referenced by name.

func (*Service) Middleware

func (s *Service) Middleware(p Policy, keyFn KeyFunc) func(http.Handler) http.Handler

Middleware enforces policy p, keyed by keyFn (defaults to ClientIP). It sets the standard X-RateLimit-* headers and responds 429 with Retry-After when the limit is exceeded.

func (*Service) Policy

func (s *Service) Policy(name string) (Policy, bool)

Policy returns a previously defined policy by name.

func (*Service) WithStore

func (s *Service) WithStore(store Store) *Service

WithStore swaps the backing store (e.g. a Redis-backed one).

type Store

type Store interface {
	// Take attempts to consume one token for key under policy p at time now.
	// It returns whether the request is allowed, the tokens remaining, and the
	// time at which a token will next be available (the reset).
	Take(key string, p Policy, now time.Time) (allowed bool, remaining int, reset time.Time)
}

Store holds per-key limiter state. The default is in-memory; implement this to back the limiter with Redis (via the cache plugin) for multi-instance use.

Jump to

Keyboard shortcuts

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