servex

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 26, 2025 License: MIT Imports: 27 Imported by: 0

README

Servex - Lightweight HTTP(S) Server Package

Go Version GoDoc Build GoReport

Servex is a lightweight HTTP(S) server package built using Go's net/http and gorilla/mux. This package is designed to easy integrate into existing net/http servers. By using gorilla/mux, it offers flexible routing capabilities with the integrated middleware for logging, authentication and panic recovery.

Table of Contents

Why Servex

Image you have a web appiction with vanila net/http handler:

func handler(w http.ResponseWriter, r *http.Request) {
    bodyBytes, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "cannot read request body", http.StatusBadRequest)
        return
    }

    var request Request
    if err := json.Unmarshal(bodyBytes, &request); err != nil {
        http.Error(w, "invalid request body", http.StatusBadRequest)
        return
    }

    // ... do something with request

    respBytes, err := json.Marshal(resp)
    if err != nil {
        http.Error(w, "cannot marshal response", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Content-Length", strconv.Itoa(len(respBytes)))

    if _, err := w.Write(respBytes); err != nil {
        http.Error(w, "cannot write response", http.StatusInternalServerError)
        return
    }
}

With Servex you can write your handler like this:

func handler(w http.ResponseWriter, r *http.Request) {
    ctx := servex.C(w, r)

    request, err := servex.ReadJSON[Request](r)
    if err != nil {
        ctx.BadRequest(err, "invalid request body")
        return
    }

    // ... do something with request

    ctx.Response(http.StatusOK, resp)
}

Less code, more focus on business logic. Implement in your handler just by calling servex.C(w, r). Look at the usage examples below to see options for starting a server with Servex in easy way.

Installation

To install the package, use the following go get command:

go get -u github.com/maxbolgarin/servex

Usage

Starting a Server

There are multiple ways to set up a Servex server:

1. Quick Start with Configuration
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// Configure the server
config := servex.BaseConfig{
    HTTP: ":8080", // HTTP address
    HTTPS: ":8443", // HTTPS address
    CertFile: "cert.pem", // TLS certificate file
    KeyFile: "key.pem", // TLS key file
}

// Set up routes
routes := func(r *mux.Router) {
    r.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, world!")
    }).Methods(http.MethodGet)
}

// Initialize and start the server
err := servex.StartWithShutdown(ctx, config, routes, servex.WithLogger(slog.Default()))
if err != nil {
    log.Fatalf("failed to start servers: %v", err)
}

// ... some code ...

cancel() // Shutdown the server
2. Using the Server Object
// Initialize and start the server
srv := servex.New(
    servex.WithReadTimeout(10*time.Second),
    servex.WithLogger(slog.Default()), 
    servex.WithCertificate(cert),
)

srv.HandleFunc("/hello", helloHandler)
srv.HandleFunc("/world", worldHandler)

if err := srv.Start(":8080", ":8443"); err != nil {
    log.Fatalf("failed to start servers: %v", err)
}

// ... some code ...

srv.Shutdown(ctx)
3. Server with Graceful Shutdown
srv := servex.New(servex.WithLogger(slog.Default()))

// Register routes
srv.R().HandleFunc("/api/v1/health", healthHandler).Methods(http.MethodGet)
srv.R("/api/v1").HandleFunc("/users", usersHandler).Methods(http.MethodGet)

// Start with automatic shutdown on context cancellation
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

if err := srv.StartWithShutdown(ctx, ":8080", ""); err != nil {
    log.Fatalf("failed to start server: %v", err)
}

// Server will shut down automatically when context is canceled
Using Context in Handlers

Servex can be integrated into existing net/http servers - you can create servex.Context based on the http.Request and http.ResponseWriter objects and use it in your handlers.

func (app *App) CreateUserHandler(w http.ResponseWriter, r *http.Request) {
    ctx := servex.C(w, r)

    userRequest, err := servex.ReadJSON[User](r)
    if err != nil {
        ctx.BadRequest(err, "invalid user")
        return
    }

    userIDResponse, err := app.CreateUser(ctx, userRequest);
    if err != nil {
        ctx.InternalServerError(err, "cannot create user")
        return
    }

    ctx.Response(http.StatusCreated, userIDResponse)
}

With servex.Context you can get the experience of working in an HTTP framework like echo inside plain net/http servers.

Context Helpers

Servex's Context provides many helper methods:

func exampleHandler(w http.ResponseWriter, r *http.Request) {
    ctx := servex.C(w, r)
    
    // Get request information
    requestID := ctx.RequestID()
    apiVersion := ctx.APIVersion() // Extracts 'v1' from paths like /api/v1/...
    userID := ctx.Path("id")       // Path parameters from URL
    sort := ctx.Query("sort")      // Query parameters ?sort=asc
    
    // Read and validate request bodies
    user, err := servex.ReadJSON[User](r)
    // OR with validation if User implements Validate() method
    user, err := servex.ReadAndValidate[User](r)
    
    // Handle cookies
    cookie, _ := ctx.Cookie("session")
    ctx.SetCookie("session", "token123", 3600, true, true)
    
    // Send responses with proper headers
    ctx.Response(http.StatusOK, map[string]string{"status": "success"})
    
    // Or handle errors with consistent formatting
    ctx.BadRequest(err, "invalid input: %s", err.Error())
    ctx.NotFound(err, "user not found")
    ctx.InternalServerError(err, "database error")
}
Authentication

Servex includes a built-in JWT-based authentication system:

1. Setting Up Authentication
// Create an in-memory auth database
memoryDB := servex.NewMemoryAuthDatabase()

// Configure the server with authentication
srv := servex.New(
    servex.WithAuth(servex.AuthConfig{
        Database: memoryDB,
        RolesOnRegister: []servex.UserRole{"user"}, // Default roles for new users
        AccessTokenDuration: 15 * time.Minute,
        RefreshTokenDuration: 7 * 24 * time.Hour,
        InitialUsers: []servex.InitialUser{
            {Username: "admin", Password: "admin123", Roles: []servex.UserRole{"admin", "user"}},
        },
    }),
)

// Authentication routes are automatically registered under /auth/...
// - POST /auth/register - Register new user
// - POST /auth/login - Login and get tokens
// - POST /auth/refresh - Refresh access token
// - POST /auth/logout - Logout (invalidate refresh token)
// - GET /auth/me - Get current user info (requires authentication)

// Create protected routes
srv.HandleFuncWithAuth("/admin", adminHandler, "admin") // Only users with "admin" role can access
srv.HFA("/protected", protectedHandler, "user")         // Short form for HandleFuncWithAuth
2. Authentication in Existing Handlers
func (app *App) AdminOnlyHandler(w http.ResponseWriter, r *http.Request) {
    ctx := servex.C(w, r)
    
    // Get user ID from context (set by auth middleware)
    userID, ok := r.Context().Value(servex.UserContextKey{}).(string)
    if !ok {
        ctx.Unauthorized(errors.New("not authenticated"), "authentication required")
        return
    }
    
    // Get user roles 
    roles, _ := r.Context().Value(servex.RoleContextKey{}).([]servex.UserRole)
    
    // ... handle the request
    
    ctx.Response(http.StatusOK, result)
}
3. Login Flow Example
// Client sends login request
// POST /auth/login
// {"username": "user1", "password": "pass123"}

// Server responds with:
// 200 OK
// {
//   "id": "user-id-123",
//   "username": "user1",
//   "roles": ["user"],
//   "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
// }
// Set-Cookie: refresh_token=token123; HttpOnly; Secure; SameSite=Strict

// Client uses accessToken in Authorization header
// GET /api/protected
// Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

// When access token expires, client sends refresh request
// POST /auth/refresh
// (refresh_token cookie is sent automatically)
Rate Limiter

Servex includes a built-in rate limiting middleware:

// Configure and start server with rate limiting
srv := servex.New(
    servex.WithRPS(100), // 100 requests per second
    servex.WithRateLimitExcludePaths("/health", "/docs")
)


// Rate limiting by username for login attempts
customKeyFunc := func(r *http.Request) string {
    // Extract username from request for more accurate rate limiting
    // on login endpoints
    if r.URL.Path == "/login" {
        username := r.FormValue("username")
        if username != "" {
            return "user:" + username
        }
    }
    // Fall back to IP-based limiting
    return r.RemoteAddr
}

srv := servex.New(
    servex.WithRateLimitConfig(servex.RateLimitConfig{
        RequestsPerInterval: 5,
        Interval:            time.Minute,
        KeyFunc:             customKeyFunc,
    }),
)

Configuration Options

Servex allows customization through options passed during server instantiation. Here's how you can configure it:

  • WithCertificate: Set TLS certificate for HTTPS.
  • WithReadTimeout: Customize read timeout duration.
  • WithIdleTimeout: Customize idle timeout duration.
  • WithAuthToken: Set an authorization token for middleware-based authentication.
  • WithMetrics: Attach a metrics handler to track requests.
  • WithLogger: Specify a custom logging mechanism.
  • WithRequestLogger: Customizes request logging separately from server logging.
  • WithAuth: Configure JWT-based authentication with roles.
  • WithRateLimitConfig: Configure rate limiting with custom options.
  • WithRPM: Set rate limit to requests per minute.
  • WithRPS: Set rate limit to requests per second.

Example:

options := []servex.Option{
    servex.WithReadTimeout(30 * time.Second),
    servex.WithIdleTimeout(120 * time.Second),
    servex.WithAuthToken("s3cret"),
    servex.WithRPS(10), // Limit to 10 requests per second
}

// Create server with options
server := servex.NewWithOptions(servex.Options{
    ReadTimeout:   30 * time.Second,
    IdleTimeout:   120 * time.Second,
    AuthToken:     "s3cret",
    RateLimit: servex.RateLimitConfig{
        RequestsPerInterval: 10,
        Interval:            time.Second,
        BurstSize:           20, // Allow bursts of up to 20 requests
        ExcludePaths:        []string{"/health", "/metrics"},
    },
})

Key Features

  • Simplified HTTP Handling: Context-based request/response handling with type safety
  • Flexible Routing: Powered by gorilla/mux with subrouters, path variables, etc.
  • Built-in Authentication: JWT-based authentication with refresh tokens and role-based access
  • Rate Limiting: Built-in middleware for restricting request frequency with customizable options
  • Structured Error Responses: Consistent error formatting across all endpoints
  • Graceful Shutdown: Clean shutdown capabilities for both HTTP and HTTPS servers
  • TLS Support: Easy HTTPS configuration with certificate management
  • Integrated Middleware: Logging, authentication, panic recovery out of the box
  • Type-Safe JSON Handling: Generic functions for reading and validating JSON requests

Pros and Cons

Pros
  • Lightweight: Minimal overhead, quick to integrate.
  • Flexible Routing: Powered by gorilla/mux, allowing for precise routing and path handling.
  • Built-in Middleware: Includes logging, authentication, and panic recovery.
  • Context-based Request Handling: No more boilerplate for reading requests and sending responses.
  • Type Safety: Generics support for JSON handling with less boilerplate.
  • Roles-Based Auth: Built-in JWT authentication with refresh tokens and role-based access control.
Cons
  • Basic Documentation: Might require reading docs and understanding of underlying gorilla/mux for advanced use cases.
  • Limited Database Options: Currently supports only in-memory database for auth out of the box. You should implement it's own database it you want to use auth.
  • Auth limitations: Auth handling is very basic.

Contributing

If you'd like to contribute to servex, submit a pull request or open an issue.

License

Servex is licensed under the MIT License. See the LICENSE file for more information.

Documentation

Overview

Package servex provides a basic HTTP(S) server based on a net/http and gorilla/mux.

Index

Constants

View Source
const (
	IDDBField                    = "id"
	IDDBBsonField                = "_id"
	UsernameDBField              = "username"
	RolesDBField                 = "roles"
	PasswordHashDBField          = "password_hash"
	RefreshTokenHashDBField      = "refresh_token_hash"
	RefreshTokenExpiresAtDBField = "refresh_token_expires_at"
)
View Source
const (
	// RequestIDLogField adds request ID to logs.
	RequestIDLogField = "request_id"
	// IPLogField adds remote IP address to logs.
	IPLogField = "ip"
	// UserAgentLogField adds client's User-Agent to logs.
	UserAgentLogField = "user_agent"
	// URLLogField adds request URL to logs.
	URLLogField = "url"
	// MethodLogField adds request method to logs like GET or POST.
	MethodLogField = "method"
	// ProtoLogField adds request protocol to logs like HTTP/1.1 or HTTP/2.
	ProtoLogField = "proto"
)
View Source
const (
	// MIMETypeAAC defines the MIME type for AAC audio.
	MIMETypeAAC = "audio/aac"

	// MIMETypeABW defines the MIME type for AbiWord documents.
	MIMETypeABW = "application/x-abiword"

	// MIMETypeAPNG defines the MIME type for Animated Portable Network Graphics (APNG).
	MIMETypeAPNG = "image/apng"

	// MIMETypeARC defines the MIME type for Archive documents (multiple files embedded).
	MIMETypeARC = "application/x-freearc"

	// MIMETypeAVIF defines the MIME type for AVIF images.
	MIMETypeAVIF = "image/avif"

	// MIMETypeAVI defines the MIME type for AVI (Audio Video Interleave).
	MIMETypeAVI = "video/x-msvideo"

	// MIMETypeAZW defines the MIME type for Amazon Kindle eBook format.
	MIMETypeAZW = "application/vnd.amazon.ebook"

	// MIMETypeBIN defines the MIME type for any kind of binary data.
	MIMETypeBIN = "application/octet-stream"

	// MIMETypeBMP defines the MIME type for Windows OS/2 Bitmap Graphics.
	MIMETypeBMP = "image/bmp"

	// MIMETypeBZ defines the MIME type for BZip archives.
	MIMETypeBZ = "application/x-bzip"

	// MIMETypeBZ2 defines the MIME type for BZip2 archives.
	MIMETypeBZ2 = "application/x-bzip2"

	// MIMETypeCDA defines the MIME type for CD audio.
	MIMETypeCDA = "application/x-cdf"

	// MIMETypeCSH defines the MIME type for C-Shell scripts.
	MIMETypeCSH = "application/x-csh"

	// MIMETypeCSS defines the MIME type for Cascading Style Sheets (CSS).
	MIMETypeCSS = "text/css"

	// MIMETypeCSV defines the MIME type for Comma-separated values (CSV).
	MIMETypeCSV = "text/csv"

	// MIMETypeDOC defines the MIME type for Microsoft Word.
	MIMETypeDOC = "application/msword"

	// MIMETypeDOCX defines the MIME type for Microsoft Word (OpenXML).
	MIMETypeDOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"

	// MIMETypeEOT defines the MIME type for MS Embedded OpenType fonts.
	MIMETypeEOT = "application/vnd.ms-fontobject"

	// MIMETypeEPUB defines the MIME type for Electronic publications (EPUB).
	MIMETypeEPUB = "application/epub+zip"

	// MIMETypeGZ defines the MIME type for GZip Compressed Archives.
	MIMETypeGZ = "application/gzip"

	// MIMETypeGIF defines the MIME type for Graphics Interchange Format (GIF).
	MIMETypeGIF = "image/gif"

	// MIMETypeHTML defines the MIME type for HyperText Markup Language (HTML).
	MIMETypeHTML = "text/html"

	// MIMETypeICO defines the MIME type for Icon format.
	MIMETypeICO = "image/vnd.microsoft.icon"

	// MIMETypeICS defines the MIME type for iCalendar format.
	MIMETypeICS = "text/calendar"

	// MIMETypeJAR defines the MIME type for Java Archives (JAR).
	MIMETypeJAR = "application/java-archive"

	// MIMETypeJPEG defines the MIME type for JPEG images.
	MIMETypeJPEG = "image/jpeg"

	// MIMETypeJS defines the MIME type for JavaScript.
	MIMETypeJS = "text/javascript"

	// MIMETypeJSON defines the MIME type for JSON format.
	MIMETypeJSON = "application/json"

	// MIMETypeJSONLD defines the MIME type for JSON-LD format.
	MIMETypeJSONLD = "application/ld+json"

	// MIMETypeMIDI defines the MIME type for Musical Instrument Digital Interface (MIDI).
	MIMETypeMIDI = "audio/midi"

	// MIMETypeMJS defines the MIME type for JavaScript modules.
	MIMETypeMJS = "text/javascript"

	// MIMETypeMP3 defines the MIME type for MP3 audio.
	MIMETypeMP3 = "audio/mpeg"

	// MIMETypeMP4 defines the MIME type for MP4 video.
	MIMETypeMP4 = "video/mp4"

	// MIMETypeMPEG defines the MIME type for MPEG Video.
	MIMETypeMPEG = "video/mpeg"

	// MIMETypeMPKG defines the MIME type for Apple Installer Packages.
	MIMETypeMPKG = "application/vnd.apple.installer+xml"

	// MIMETypeODP defines the MIME type for OpenDocument presentation documents.
	MIMETypeODP = "application/vnd.oasis.opendocument.presentation"

	// MIMETypeODS defines the MIME type for OpenDocument spreadsheet documents.
	MIMETypeODS = "application/vnd.oasis.opendocument.spreadsheet"

	// MIMETypeODT defines the MIME type for OpenDocument text documents.
	MIMETypeODT = "application/vnd.oasis.opendocument.text"

	// MIMETypeOGA defines the MIME type for Ogg audio.
	MIMETypeOGA = "audio/ogg"

	// MIMETypeOGV defines the MIME type for Ogg video.
	MIMETypeOGV = "video/ogg"

	// MIMETypeOGX defines the MIME type for Ogg.
	MIMETypeOGX = "application/ogg"

	// MIMETypeOPUS defines the MIME type for Opus audio in Ogg container.
	MIMETypeOPUS = "audio/ogg"

	// MIMETypeOTF defines the MIME type for OpenType fonts.
	MIMETypeOTF = "font/otf"

	// MIMETypePNG defines the MIME type for Portable Network Graphics.
	MIMETypePNG = "image/png"

	// MIMETypePDF defines the MIME type for Adobe Portable Document Format (PDF).
	MIMETypePDF = "application/pdf"

	// MIMETypePHP defines the MIME type for Hypertext Preprocessor (Personal Home Page).
	MIMETypePHP = "application/x-httpd-php"

	// MIMETypePPT defines the MIME type for Microsoft PowerPoint.
	MIMETypePPT = "application/vnd.ms-powerpoint"

	// MIMETypePPTX defines the MIME type for Microsoft PowerPoint (OpenXML).
	MIMETypePPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation"

	// MIMETypeRAR defines the MIME type for RAR archives.
	MIMETypeRAR = "application/vnd.rar"

	// MIMETypeRTF defines the MIME type for Rich Text Format (RTF).
	MIMETypeRTF = "application/rtf"

	// MIMETypeSH defines the MIME type for Bourne shell scripts.
	MIMETypeSH = "application/x-sh"

	// MIMETypeSVG defines the MIME type for Scalable Vector Graphics (SVG).
	MIMETypeSVG = "image/svg+xml"

	// MIMETypeTAR defines the MIME type for Tape Archives (TAR).
	MIMETypeTAR = "application/x-tar"

	// MIMETypeTIFF defines the MIME type for Tagged Image File Format (TIFF).
	MIMETypeTIFF = "image/tiff"

	// MIMETypeTS defines the MIME type for MPEG transport stream.
	MIMETypeTS = "video/mp2t"

	// MIMETypeTTF defines the MIME type for TrueType Fonts.
	MIMETypeTTF = "font/ttf"

	// MIMETypeTXT defines the MIME type for Plain Text.
	MIMETypeTXT = "text/plain"

	// MIMETypeText is an alias for MIMETypeTXT.
	MIMETypeText = MIMETypeTXT

	// MIMETypePlain is an alias for MIMETypeTXT.
	MIMETypePlain = MIMETypeTXT

	// MIMETypeVSD defines the MIME type for Microsoft Visio.
	MIMETypeVSD = "application/vnd.visio"

	// MIMETypeWAV defines the MIME type for Waveform Audio Format.
	MIMETypeWAV = "audio/wav"

	// MIMETypeWEBA defines the MIME type for WEBM audio.
	MIMETypeWEBA = "audio/webm"

	// MIMETypeWEBM defines the MIME type for WEBM video.
	MIMETypeWEBM = "video/webm"

	// MIMETypeWEBP defines the MIME type for WEBP images.
	MIMETypeWEBP = "image/webp"

	// MIMETypeWOFF defines the MIME type for Web Open Font Format (WOFF).
	MIMETypeWOFF = "font/woff"

	// MIMETypeWOFF2 defines the MIME type for Web Open Font Format (WOFF2).
	MIMETypeWOFF2 = "font/woff2"

	// MIMETypeXHTML defines the MIME type for XHTML.
	MIMETypeXHTML = "application/xhtml+xml"

	// MIMETypeXLS defines the MIME type for Microsoft Excel.
	MIMETypeXLS = "application/vnd.ms-excel"

	// MIMETypeXLSX defines the MIME type for Microsoft Excel (OpenXML).
	MIMETypeXLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

	// MIMETypeXML defines the MIME type for XML.
	MIMETypeXML = "application/xml"

	// MIMETypeXUL defines the MIME type for XUL.
	MIMETypeXUL = "application/vnd.mozilla.xul+xml"

	// MIMETypeZIP defines the MIME type for ZIP archives.
	MIMETypeZIP = "application/zip"

	// MIMEType3GP defines the MIME type for 3GPP audio/video containers.
	MIMEType3GP = "video/3gpp"

	// MIMEType3G2 defines the MIME type for 3GPP2 audio/video containers.
	MIMEType3G2 = "video/3gpp2"

	// MIMEType7Z defines the MIME type for 7-zip archives.
	MIMEType7Z = "application/x-7z-compressed"
)
View Source
const (
	// GET is the HTTP GET method.
	GET = http.MethodGet

	// HEAD is the HTTP HEAD method.
	HEAD = http.MethodHead

	// POST is the HTTP POST method.
	POST = http.MethodPost

	// PUT is the HTTP PUT method.
	PUT = http.MethodPut

	// PATCH is the HTTP PATCH method.
	PATCH = http.MethodPatch

	// DELETE is the HTTP DELETE method.
	DELETE = http.MethodDelete

	// CONNECT is the HTTP CONNECT method.
	CONNECT = http.MethodConnect

	// OPTIONS is the HTTP OPTIONS method.
	OPTIONS = http.MethodOptions

	// TRACE is the HTTP TRACE method.
	TRACE = http.MethodTrace
)

HTTP methods shortcuts

Variables

View Source
var (
	// ListenAddressRegexp is used to match "ip:port" or ":port" strings or kuber domains with port.
	ListenAddressRegexp = regexp.MustCompile(`^[\w\-\/:@\.]*:[0-9]{1,5}$`)
)

Functions

func GetFromContext added in v1.3.0

func GetFromContext[T any](r *http.Request, key any) (empty T)

func GetTLSConfig added in v1.1.0

func GetTLSConfig(cert *tls.Certificate) *tls.Config

GetTLSConfig creates a *tls.Config suitable for an HTTPS server using the provided certificate. It returns nil if the certificate is nil. The config enables HTTP/2, prefers server cipher suites, sets minimum TLS version to 1.2, and includes a list of secure cipher suites and curve preferences.

func MakeRawRequest

func MakeRawRequest(path, host string, headers map[string]string, body ...string) []byte

MakeRawRequest makes a raw HTTP request in a form of []byte.

func MakeRawResponse

func MakeRawResponse(code int, headers map[string]string, body ...string) []byte

MakeRawResponse makes a raw HTTP response in a form of []byte.

func Read added in v1.2.0

func Read(r *http.Request) ([]byte, error)

Read reads the request body.

func ReadAndValidate

func ReadAndValidate[T interface{ Validate() error }](r *http.Request) (T, error)

ReadAndValidate reads a JSON from the request body to a variable of the provided type and validates it.

func ReadCertificate

func ReadCertificate(cert, key []byte) (tls.Certificate, error)

ReadCertificate is a function that reads a TLS certificate from the given cert and key bytes and returns a tls.Certificate instance.

func ReadCertificateFromFile

func ReadCertificateFromFile(certFile, keyFile string) (tls.Certificate, error)

ReadCertificateFromFile is a function that reads a TLS certificate from the given cert and key files and returns a tls.Certificate instance.

func ReadFile added in v1.2.0

func ReadFile(r *http.Request, fileKey string) ([]byte, *multipart.FileHeader, error)

ReadFile reads a file from the request body. fileKey is the key of the file in the request. It returns the file bytes, the file header and an error.

func ReadJSON

func ReadJSON[T any](r *http.Request) (T, error)

ReadJSON reads a JSON from the request body to a variable of the provided type.

func RegisterLoggingMiddleware added in v1.1.0

func RegisterLoggingMiddleware(router MiddlewareRouter, logger RequestLogger, metrics Metrics, noLogClientErrors ...bool)

RegisterLoggingMiddleware registers a middleware that logs incoming requests. It logs details such as request method, path, status code, duration, and any errors encountered during processing. It also integrates with a Metrics handler if provided. If the logger is nil, it defaults to a BaseRequestLogger using slog.Default(). Requests can be excluded from logging by calling ctx.NoLog() within the handler.

func RegisterRateLimitMiddleware added in v1.1.0

func RegisterRateLimitMiddleware(router MiddlewareRouter, cfg RateLimitConfig)

RegisterRateLimitMiddleware adds rate limiting middleware to the router. If the config is not enabled, no middleware will be registered.

func RegisterRecoverMiddleware added in v1.1.0

func RegisterRecoverMiddleware(router MiddlewareRouter, logger ErrorLogger)

RegisterRecoverMiddleware registers a middleware that recovers from panics in HTTP handlers. If a panic occurs, it logs the error and stack trace using the provided logger (defaulting to slog.Default() if nil) and sends a 500 Internal Server Error response only if no response headers have been written yet.

func RegisterSimpleAuthMiddleware added in v1.1.0

func RegisterSimpleAuthMiddleware(router MiddlewareRouter, authToken string)

RegisterSimpleAuthMiddleware registers a middleware for simple token-based authentication. It checks the "Authorization" header for a token matching the provided authToken. It supports both "Bearer <token>" and "<token>" formats. If the authToken is empty, no middleware is registered. If the header is missing or the token is invalid, it responds with 401 Unauthorized.

func Start

func Start(cfg BaseConfig, handlerSetter func(*mux.Router), opts ...Option) (shutdown func(context.Context) error, err error)

Start starts the server with the provided BaseConfig and [Option]s. It returns an error if there was an error starting either of the servers. You should provide a function that sets the handlers for the server to the router. It returns shutdown function so you should shutdown the server manually.

func StartWithShutdown

func StartWithShutdown(ctx context.Context, cfg BaseConfig, handlerSetter func(*mux.Router), opts ...Option) error

Start starts the server with the provided BaseConfig and [Option]s. It returns an error if there was an error starting either of the servers. You should provide a function that sets the handlers for the server to the router. It shutdowns the server when the context is closed (it starts a goroutine to check [Context.Done]).

Types

type AuthConfig added in v1.1.0

type AuthConfig struct {
	// Database is the interface for user data persistence.
	Database AuthDatabase

	// JWTAccessSecret is the secret key used for signing access tokens (hex encoded).
	// If empty, a random key will be generated.
	JWTAccessSecret string

	// JWTRefreshSecret is the secret key used for signing refresh tokens (hex encoded).
	// If empty, a random key will be generated.
	JWTRefreshSecret string

	// AccessTokenDuration specifies the validity duration for access tokens.
	// Defaults to 5 minutes if not set.
	AccessTokenDuration time.Duration

	// RefreshTokenDuration specifies the validity duration for refresh tokens.
	// Defaults to 7 days if not set.
	RefreshTokenDuration time.Duration

	// IssuerNameInJWT is the issuer name included in the JWT claims.
	// Defaults to "testing" if not set.
	IssuerNameInJWT string

	// RefreshTokenCookieName is the name of the cookie used to store the refresh token.
	// Defaults to "_servexrt" if not set.
	RefreshTokenCookieName string

	// AuthBasePath is the base path for the authentication API endpoints.
	// Defaults to "/api/v1/auth" if not set.
	AuthBasePath string

	// RolesOnRegister are the roles assigned to a newly registered user.
	RolesOnRegister []UserRole

	// InitialUsers is a list of initial users to be created.
	InitialUsers []InitialUser

	// NotRegisterRoutes, if true, prevents the automatic registration of default auth routes.
	NotRegisterRoutes bool
	// contains filtered or unexported fields
}

AuthConfig holds the configuration specific to authentication.

type AuthDatabase added in v1.1.0

type AuthDatabase interface {
	// NewUser creates a new user in the database.
	NewUser(ctx context.Context, username string, passwordHash string, roles ...UserRole) (string, error)

	// FindByID finds a user by their ID.
	FindByID(ctx context.Context, id string) (user User, exists bool, err error)
	// FindByUsername finds a user by their username.
	FindByUsername(ctx context.Context, username string) (user User, exists bool, err error)
	// FindAll retrieves all users from the database.
	FindAll(ctx context.Context) ([]User, error)

	// UpdateUser updates a user's information in the database.
	// Fields are updated only if the corresponding pointers are not nil.
	UpdateUser(ctx context.Context, id string, diff *UserDiff) error
}

AuthDatabase defines the interface for interacting with the user database.

type AuthManager added in v1.1.0

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

AuthManager handles authentication and authorization logic.

func NewAuthManager added in v1.1.0

func NewAuthManager(cfg AuthConfig) *AuthManager

NewAuthManager creates a new AuthManager with the provided configuration. It initializes default values for configuration fields if they are not provided and generates random secrets if JWT secrets are empty.

func (*AuthManager) CreateUser added in v1.1.0

func (h *AuthManager) CreateUser(ctx context.Context, username, password string, roles ...UserRole) error

CreateUser provides a programmatic way to create or update a user. If the user already exists (based on username), it updates their password and roles. If the user does not exist, it creates a new user with the provided details.

func (*AuthManager) GetAllUsersHandler added in v1.1.0

func (h *AuthManager) GetAllUsersHandler(w http.ResponseWriter, r *http.Request)

GetAllUsersHandler handles the HTTP request to retrieve all users. Note: This handler is intended for administrative purposes and might require specific roles. The corresponding route registration is commented out by default.

func (*AuthManager) GetCurrentUserHandler added in v1.1.0

func (h *AuthManager) GetCurrentUserHandler(w http.ResponseWriter, r *http.Request)

GetCurrentUserHandler handles the HTTP request to retrieve the details of the currently authenticated user.

func (*AuthManager) LoginHandler added in v1.1.0

func (h *AuthManager) LoginHandler(w http.ResponseWriter, r *http.Request)

LoginHandler handles the HTTP request for user login.

func (*AuthManager) LogoutHandler added in v1.1.0

func (h *AuthManager) LogoutHandler(w http.ResponseWriter, r *http.Request)

LogoutHandler handles the HTTP request for user logout. It invalidates the refresh token associated with the current session.

func (*AuthManager) RefreshHandler added in v1.1.0

func (h *AuthManager) RefreshHandler(w http.ResponseWriter, r *http.Request)

RefreshHandler handles the HTTP request for refreshing access tokens using a refresh token cookie.

func (*AuthManager) RegisterHandler added in v1.1.0

func (h *AuthManager) RegisterHandler(w http.ResponseWriter, r *http.Request)

RegisterHandler handles the HTTP request for user registration.

func (*AuthManager) RegisterRoutes added in v1.1.0

func (h *AuthManager) RegisterRoutes(r *mux.Router)

RegisterRoutes registers the authentication-related HTTP routes on the provided router.

func (*AuthManager) UpdateUserRoleHandler added in v1.1.0

func (h *AuthManager) UpdateUserRoleHandler(w http.ResponseWriter, r *http.Request)

UpdateUserRoleHandler handles the HTTP request to update a user's roles. Note: This handler is intended for administrative purposes and might require specific roles. The corresponding route registration is commented out by default.

func (*AuthManager) WithAuth added in v1.1.0

func (m *AuthManager) WithAuth(next http.HandlerFunc, roles ...UserRole) http.HandlerFunc

WithAuth is an HTTP middleware that enforces authentication and authorization. It checks for a valid JWT access token in the Authorization header. If roles are provided, it verifies that the authenticated user has at least one of the required roles. The user ID and roles are added to the request context.

type BaseConfig

type BaseConfig struct {
	// HTTP is an address to start HTTP listener on.
	HTTP string `yaml:"http" json:"http" env:"SERVER_HTTP"`

	// HTTPS is an address to start HTTPS listener on.
	HTTPS string `yaml:"https" json:"https" env:"SERVER_HTTPS"`

	// CertFile is a path to the TLS certificate file in case of HTTPS.
	CertFile string `yaml:"cert_file" json:"cert_file" env:"SERVER_CERT_FILE"`

	// KeyFile is a path to the TLS key file in case of HTTPS.
	KeyFile string `yaml:"key_file" json:"key_file" env:"SERVER_KEY_FILE"`

	// AuthToken is a token for authorization in Authorization header.
	AuthToken string `yaml:"auth_token" json:"auth_token" env:"SERVER_AUTH_TOKEN"`
}

BaseConfig represents the base configuration for a server without additional options. You can use it as a base for your own configuration.

func (*BaseConfig) Validate

func (c *BaseConfig) Validate() error

Validate checks if the BaseConfig is valid. It ensures that at least one of HTTP or HTTPS address is provided and that addresses match the required format.

type BaseRequestLogger

type BaseRequestLogger struct {
	Logger
}

func (*BaseRequestLogger) Log

type Context

type Context struct {
	context.Context
	// contains filtered or unexported fields
}

Context holds data and methods for handling HTTP request.

func C

C returns a new context for the provided request. It is a shortcut for NewContext.

func NewContext

func NewContext(w http.ResponseWriter, r *http.Request) *Context

NewContext returns a new context for the provided request.

func (*Context) APIVersion

func (ctx *Context) APIVersion() string

APIVersion returns the API version of the handler from the path. It returns an empty string if not found.

func (*Context) BadGateway

func (ctx *Context) BadGateway(err error, msg string, args ...any)

BadGateway handles an error by returning an HTTP error response with status code 502. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) BadRequest

func (ctx *Context) BadRequest(err error, msg string, args ...any)

BadRequest handles an error by returning an HTTP error response with status code 400. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) Conflict

func (ctx *Context) Conflict(err error, msg string, args ...any)

Conflict handles an error by returning an HTTP error response with status code 409. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) Cookie

func (ctx *Context) Cookie(key string) (*http.Cookie, error)

Cookie returns the cookie with the given name.

func (*Context) Error

func (ctx *Context) Error(err error, code int, msg string, args ...any)

Error handles an error by returning an HTTP error response. You should use this method during error handling in HTTP handlers. Method sets Content-Type and Content-Length headers. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method.

func (*Context) Forbidden

func (ctx *Context) Forbidden(err error, msg string, args ...any)

Forbidden handles an error by returning an HTTP error response with status code 403. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) FormValue

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

FormValue returns the value of the form field for the given key.

func (*Context) Header

func (ctx *Context) Header(key string) string

Header returns the value of the request header with the given name. If multiple values are present, they are joined with a comma and space ", ".

func (*Context) InternalServerError

func (ctx *Context) InternalServerError(err error, msg string, args ...any)

InternalServerError handles an error by returning an HTTP error response with status code 500. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) LogFields

func (ctx *Context) LogFields(fieldsToInclude ...string) []any

LogFields returns a slice of fields to set to logger using With method. You can add fieldsToInclude to set exact fields that you need. By default it returns all fields.

func (*Context) NoLog

func (ctx *Context) NoLog()

NoLog marks to not log the request after returning from the handler.

func (*Context) NotAcceptable

func (ctx *Context) NotAcceptable(err error, msg string, args ...any)

NotAcceptable handles an error by returning an HTTP error response with status code 406. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) NotFound

func (ctx *Context) NotFound(err error, msg string, args ...any)

NotFound handles an error by returning an HTTP error response with status code 404. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) NotImplemented

func (ctx *Context) NotImplemented(err error, msg string, args ...any)

NotImplemented handles an error by returning an HTTP error response with status code 501. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) ParseUnixFromQuery

func (ctx *Context) ParseUnixFromQuery(key string) (time.Time, error)

ParseUnixFromQuery parses unix timestamp from query params to time.Time.

func (*Context) Path

func (ctx *Context) Path(key string) string

Path returns the value of the path parameter for the given key. Path parameters are the variables from the URL like "/{key}".

func (*Context) Query

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

Query returns the value of the query parameter for the given key. Query is a parameter from the URL, e.g. "abc/?key=value".

func (*Context) Read

func (ctx *Context) Read() ([]byte, error)

Read reads the request body.

func (*Context) ReadAndValidate

func (ctx *Context) ReadAndValidate(body interface{ Validate() error }) error

ReadAndValidate reads a JSON from the request body and variable and validate it. You should provide a pointer to the variable.

func (*Context) ReadFile added in v1.2.0

func (ctx *Context) ReadFile(fileKey string) ([]byte, *multipart.FileHeader, error)

ReadFile reads a file from the request body. fileKey is the key of the file in the request. It returns the file bytes, the file header and an error.

func (*Context) ReadJSON

func (ctx *Context) ReadJSON(body any) error

ReadJSON reads a JSON from the request body. You should provide a pointer to the variable.

func (*Context) RequestID

func (ctx *Context) RequestID() string

RequestID returns the request ID for the request.

func (*Context) Response

func (ctx *Context) Response(code int, bodyRaw ...any)

Response writes provided status code and body to the http.ResponseWriter. Body may be []byte, string or an object, that can be marshalled to JSON. It will write nothing in case of body==nil sending response headers with status code only. Method sets Content-Type and Content-Length headers. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method.

func (*Context) ResponseFile added in v1.1.2

func (ctx *Context) ResponseFile(filename string, mimeType string, body []byte)

func (*Context) ServiceUnavailable

func (ctx *Context) ServiceUnavailable(err error, msg string, args ...any)

ServiceUnavailable handles an error by returning an HTTP error response with status code 503. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) SetContentType

func (ctx *Context) SetContentType(mimeType string, charset ...string)

SetContentType sets the Content-Type header.

func (*Context) SetCookie

func (ctx *Context) SetCookie(name, value string, maxAge int, secure, httpOnly bool)

SetCookie sets the cookie with the given name, value, maxAge, secure and httpOnly. maxAge is the time in seconds until the cookie expires. If maxAge < 0, the cookie is deleted. secure specifies if the cookie should only be transmitted over HTTPS. httpOnly prevents the cookie from being accessed through JavaScript, enhancing security against XSS attacks.

func (*Context) SetHeader

func (ctx *Context) SetHeader(key string, value ...string)

SetHeader sets the value of the response header with the given name. If multiple values are provided, they are added to the header.

func (*Context) SetRawCookie

func (ctx *Context) SetRawCookie(c *http.Cookie)

SetRawCookie sets the cookie with the given http.Cookie.

func (*Context) SetSendErrorToClient added in v1.3.0

func (ctx *Context) SetSendErrorToClient(sendErrorToClient bool)

SetSendErrorToClient add golang error to response body in case of error.

func (*Context) TooManyRequests

func (ctx *Context) TooManyRequests(err error, msg string, args ...any)

TooManyRequests handles an error by returning an HTTP error response with status code 429. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) Unauthorized

func (ctx *Context) Unauthorized(err error, msg string, args ...any)

Unauthorized handles an error by returning an HTTP error response with status code 401. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

func (*Context) UnprocessableEntity

func (ctx *Context) UnprocessableEntity(err error, msg string, args ...any)

StatusUnprocessableEntity handles an error by returning an HTTP error response with status code 422. You should not modify the http.ResponseWriter after calling this method. You will probably want to return from your handler after calling this method. It is a shortcut for Context.Error.

type ErrorLogger added in v1.1.0

type ErrorLogger interface {
	// Error is using to log request errors, panics, serve errors and shutodwn in StartContext errors
	Error(msg string, fields ...any)
}

type ErrorResponse

type ErrorResponse struct {
	Message string `json:"message"`
}

ErrorResponse represents a JSON for an error response.

type InitialUser added in v1.1.0

type InitialUser struct {
	// Username is the username of the user.
	Username string

	// Password is the password of the user.
	Password string

	// Roles are the roles assigned to the user.
	Roles []UserRole
}

InitialUser represents a user to be created during server startup.

type Logger

type Logger interface {
	// Debug is using to log successful requests.
	Debug(msg string, fields ...any)
	// Info is using to log 'http(s) server started'
	Info(msg string, fields ...any)
	// Error is using to log request errors, panics, serve errors and shutodwn in StartContext errors
	Error(msg string, fields ...any)
}

Logger is an interface for logger to log messages.

type MemoryAuthDatabase added in v1.1.0

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

MockAuthDatabase provides a mock implementation of the AuthDatabase interface for testing.

func NewMemoryAuthDatabase added in v1.1.0

func NewMemoryAuthDatabase() *MemoryAuthDatabase

func (*MemoryAuthDatabase) FindAll added in v1.1.0

func (db *MemoryAuthDatabase) FindAll(ctx context.Context) ([]User, error)

func (*MemoryAuthDatabase) FindByID added in v1.1.0

func (db *MemoryAuthDatabase) FindByID(ctx context.Context, id string) (User, bool, error)

func (*MemoryAuthDatabase) FindByUsername added in v1.1.0

func (db *MemoryAuthDatabase) FindByUsername(ctx context.Context, username string) (User, bool, error)

func (*MemoryAuthDatabase) NewUser added in v1.1.0

func (db *MemoryAuthDatabase) NewUser(ctx context.Context, username string, passwordHash string, roles ...UserRole) (string, error)

func (*MemoryAuthDatabase) UpdateUser added in v1.1.0

func (db *MemoryAuthDatabase) UpdateUser(ctx context.Context, id string, diff *UserDiff) error

type Metrics

type Metrics interface {
	// HandleRequest is called on each request to collect metrics.
	HandleRequest(r *http.Request)
}

Metrics is an interface for collecting metrics on each request. [Metrics.HandleRequest] is called on each request.

type MiddlewareRouter added in v1.1.0

type MiddlewareRouter interface {
	// Use adds one or more middleware functions to the router.
	Use(middleware ...mux.MiddlewareFunc)
}

MiddlewareRouter is an interface representing a router that supports adding middleware. This is typically implemented by router packages like gorilla/mux.

type Option

type Option func(*Options)

func WithAuth added in v1.1.0

func WithAuth(db AuthDatabase) Option

WithAuth sets the [Options.Auth.Database] of the Options to the given AuthDatabase and enables auth.

func WithAuthBasePath added in v1.1.0

func WithAuthBasePath(path string) Option

WithAuthBasePath sets the [Options.Auth.AuthBasePath] of the Options to the given base path.

func WithAuthConfig added in v1.1.0

func WithAuthConfig(auth AuthConfig) Option

WithAuthConfig sets the [Options.Auth] of the Options to the given AuthConfig. It panics if the provided AuthConfig.Database is nil.

func WithAuthInitialRoles added in v1.1.0

func WithAuthInitialRoles(roles ...UserRole) Option

WithAuthInitialRoles sets the [Options.Auth.InitialRoles] of the Options to the given roles.

func WithAuthInitialUsers added in v1.1.0

func WithAuthInitialUsers(users ...InitialUser) Option

WithAuthInitialUsers sets the [Options.Auth.InitialUsers] of the Options to the given users.

func WithAuthIssuer added in v1.1.0

func WithAuthIssuer(issuer string) Option

WithAuthIssuer sets the [Options.Auth.IssuerNameInJWT] of the Options to the given issuer name.

func WithAuthKey added in v1.1.0

func WithAuthKey(accessKey, refreshKey string) Option

WithAuthKey sets the [Options.Auth.JWTAccessSecret] and [Options.Auth.JWTRefreshSecret] of the Options to the given keys.

func WithAuthMemoryDatabase added in v1.1.0

func WithAuthMemoryDatabase() Option

WithAuthMemoryDatabase sets the [Options.Auth.Database] of the Options to the in-memory AuthDatabase and enables auth. NOT RECOMMENDED FOR PRODUCTION USE. It will forget all users on applications shutdown.

func WithAuthNotRegisterRoutes added in v1.1.0

func WithAuthNotRegisterRoutes(notRegisterRoutes bool) Option

WithAuthNotRegisterRoutes sets the [Options.Auth.NotRegisterRoutes] of the Options to the given value.

func WithAuthRefreshTokenCookieName added in v1.1.0

func WithAuthRefreshTokenCookieName(name string) Option

WithAuthRefreshTokenCookieName sets the [Options.Auth.RefreshTokenCookieName] of the Options to the given name.

func WithAuthToken

func WithAuthToken(t string) Option

WithAuthToken sets the [Options.AuthToken] of the Options to the given string. AuthToken is the token that will be checked in the Authorization header.

func WithAuthTokensDuration added in v1.1.0

func WithAuthTokensDuration(accessDuration, refreshDuration time.Duration) Option

WithAuthTokensDuration sets the [Options.Auth.AccessTokenDuration] and [Options.Auth.RefreshTokenDuration] of the Options to the given duration.

func WithBurstSize added in v1.1.0

func WithBurstSize(burstSize int) Option

WithBurstSize sets the [Options.RateLimit.BurstSize] of the Options to the given value.

func WithCertificate

func WithCertificate(cert tls.Certificate) Option

WithCertificate sets the TLS [Options.Certificate] to the Options. TLS certificate is required to start HTTPS server.

func WithIdleTimeout

func WithIdleTimeout(tm time.Duration) Option

WithIdleTimeout sets the [Options.IdleTimeout] of the Options to the given duration. IdleTimeout is the maximum duration an idle Keep-Alive connection will be kept open. A zero or negative value sets default value of 180 seconds.

func WithLogger

func WithLogger(l Logger) Option

WithLogger sets the Logger to the Options. If not set, there will be slog.New with slog.NewJSONHandler with logging to stderr.

func WithMetrics

func WithMetrics(m Metrics) Option

WithMetrics sets the Metrics to the Options.

func WithNoLogClientErrors added in v1.1.0

func WithNoLogClientErrors() Option

WithNoLogClientErrors disables logging of client errors with code 400-499.

func WithNoRateInAuthRoutes added in v1.1.0

func WithNoRateInAuthRoutes() Option

WithNoRateInAuthRoutes sets the [Options.RateLimit.NoRateInAuthRoutes] of the Options to true. If true, will not set rate limit for requests to auth routes automatically.

func WithNoRequestLog added in v1.1.0

func WithNoRequestLog() Option

WithNoRequestLog disables request logging.

func WithRPM added in v1.1.0

func WithRPM(rpm int) Option

WithRPM sets the [Options.RateLimit.RequestsPerInterval] of the Options to the given value. Interval is set to 1 minute.

func WithRPS added in v1.1.0

func WithRPS(rps int) Option

WithRPS sets the [Options.RateLimit.RequestsPerInterval] of the Options to the given value. Interval is set to 1 second.

func WithRateLimitConfig added in v1.1.0

func WithRateLimitConfig(rateLimit RateLimitConfig) Option

WithRateLimitConfig sets the [Options.RateLimit] of the Options to the given RateLimitConfig.

func WithRateLimitExcludePaths added in v1.1.0

func WithRateLimitExcludePaths(paths ...string) Option

WithRateLimitExcludePaths sets the [Options.RateLimit.ExcludePaths] of the Options to the given paths.

func WithRateLimitIncludePaths added in v1.1.0

func WithRateLimitIncludePaths(paths ...string) Option

WithRateLimitIncludePaths sets the [Options.RateLimit.IncludePaths] of the Options to the given paths. If empty, all paths are included except those in ExcludePaths if rate limiting is enabled.

func WithRateLimitKeyFunc added in v1.1.0

func WithRateLimitKeyFunc(keyFunc func(r *http.Request) string) Option

WithRateLimitKeyFunc sets the [Options.RateLimit.KeyFunc] of the Options to the given function.

func WithRateLimitMessage added in v1.1.0

func WithRateLimitMessage(message string) Option

WithRateLimitMessage sets the [Options.RateLimit.Message] of the Options to the given value.

func WithRateLimitStatusCode added in v1.1.0

func WithRateLimitStatusCode(statusCode int) Option

WithRateLimitStatusCode sets the [Options.RateLimit.StatusCode] of the Options to the given value.

func WithReadHeaderTimeout

func WithReadHeaderTimeout(tm time.Duration) Option

WithReadHeaderTimeout sets the [Options.ReadHeaderTimeout] of the Options to the given duration. ReadHeaderTimeout is the maximum duration for reading the request headers (without body). A zero or negative value means there will be no timeout (using ReadTimeout for all request).

func WithReadTimeout

func WithReadTimeout(tm time.Duration) Option

WithReadTimeout sets the [Options.ReadTimeout] of the Options to the given duration. ReadTimeout is the maximum duration for reading the entire request, including the body. A zero or negative value sets default value of 60 seconds.

func WithRequestLogger

func WithRequestLogger(r RequestLogger) Option

WithRequestLogger sets the RequestLogger to the Options. If not set it will use [Options.Logger] or [Options.SLogger] in debug level.

func WithRequestsPerInterval added in v1.1.0

func WithRequestsPerInterval(requestsPerInterval int, interval time.Duration) Option

WithRequestsPerInterval sets the [Options.RateLimit.RequestsPerInterval] of the Options to the given value.

func WithSendErrorToClient added in v1.3.0

func WithSendErrorToClient(sendErrorToClient bool) Option

WithSendErrorToClient sets the [Options.SendErrorToClient] of the Options to the given value.

type Options

type Options struct {
	// Certificate is the TLS certificate for the server.
	// If not set, the server will not start HTTPS server.
	Certificate *tls.Certificate

	// ReadTimeout is the maximum duration for reading the entire request.
	ReadTimeout time.Duration

	// ReadHeaderTimeout is the maximum duration for reading the request headers.
	ReadHeaderTimeout time.Duration

	// IdleTimeout is the maximum duration the server should keep connections alive.
	IdleTimeout time.Duration

	// AuthToken is the token that will be checked in the Authorization header.
	AuthToken string

	// Metrics is the metrics handler for the server.
	Metrics Metrics

	// Logger is the logger for the server.
	// If not set, there will be [slog.New] with [slog.NewJSONHandler] with logging to stderr.
	// Debug level is used to log successful requests if RequestLogger is not set.
	// Info level is used to log 'http(s) server started'
	// Error level is used to log request errors, panics, serve errors and shutodwn in StartContext errors
	Logger Logger

	// RequestLogger is the logger for the requests.
	// If not set it will use [Options.Logger].
	RequestLogger RequestLogger

	// NoLogClientErrors, if true, will not log client errors with code 400-499
	NoLogClientErrors bool

	// SendErrorToClient, if true, will send golang error to client in response body.
	SendErrorToClient bool

	// Auth is the auth configuration for the server.
	Auth AuthConfig

	// RateLimit is the rate limit configuration for the server.
	// If not set, rate limiting will be disabled.
	// If RateLimit.RequestsPerInterval is not set, it will be disabled.
	// If RateLimit.Interval is not set, it will be disabled.
	RateLimit RateLimitConfig
}

Options represents the configuration for a server.

type RateLimitConfig added in v1.1.0

type RateLimitConfig struct {
	// RequestsPerInterval is the number of operations allowed per interval.
	// If not set, rate limiting will be disabled.
	RequestsPerInterval int

	// Interval is the time after which the token bucket is refilled.
	// If not set, it will be 1 minute.
	Interval time.Duration

	// BurstSize is the maximum burst size (can exceed RequestsPerInterval temporarily).
	// If not set, it will be equal to RequestsPerInterval.
	BurstSize int

	// StatusCode is the HTTP status code returned when rate limit is exceeded.
	// Defaults to 429 (Too Many Requests) if not set.
	StatusCode int

	// Message is the response message when rate limit is exceeded.
	// Defaults to "rate limit exceeded, try again later." if not set.
	Message string

	// KeyFunc is a function that extracts the rate limit key from the request.
	// Defaults to usernameKeyFunc() if not set.
	KeyFunc func(r *http.Request) string

	// ExcludePaths are paths that should be excluded from rate limiting.
	ExcludePaths []string

	// IncludePaths are paths that should be included in rate limiting.
	// If empty, all paths are included except those in ExcludePaths if rate limiting is enabled.
	IncludePaths []string

	// NoRateInAuthRoutes, if true, will not rate limit requests to auth routes.
	NoRateInAuthRoutes bool
}

RateLimitConfig holds configuration for the rate limiter middleware.

type RequestLogBundle

type RequestLogBundle struct {
	Request           *http.Request
	RequestID         string
	Error             error
	ErrorMessage      string
	StatusCode        int
	StartTime         time.Time
	NoLogClientErrors bool
}

RequestLogBundle represents a bundle of information for logging a request.

type RequestLogger

type RequestLogger interface {
	Log(RequestLogBundle)
}

RequestLogger is an interface for logging requests. [RequestLogger.Log] is called at the end of each request after returning from handler.

type RoleContextKey added in v1.1.0

type RoleContextKey struct{}

type Server

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

Server represents an HTTP server.

func New

func New(ops ...Option) *Server

New creates a new instance of the Server. You can provide a list of options using With* methods. Server without Certificate can serve only plain HTTP.

func NewWithOptions

func NewWithOptions(opts Options) *Server

NewWithOptions creates a new instance of the Server with the provided Options.

func (*Server) AddMiddleware

func (s *Server) AddMiddleware(middleware ...func(http.Handler) http.Handler)

AddMiddleware adds one or more mux.MiddlewareFunc to the router.

func (*Server) AuthManager added in v1.1.0

func (s *Server) AuthManager() *AuthManager

AuthManager returns AuthManager, it may be useful if you want to work with auth manually. It returns nil if auth is not enabled (database is not set).

func (*Server) H added in v1.1.0

func (s *Server) H(path string, h http.Handler, methods ...string) *mux.Route

H is a shortcut for Server.Handle.

func (*Server) HA added in v1.1.0

func (s *Server) HA(path string, f http.HandlerFunc, roles ...UserRole) *mux.Route

HA is a shortcut for Server.HandleWithAuth.

func (*Server) HF added in v1.1.0

func (s *Server) HF(path string, f http.HandlerFunc, methods ...string) *mux.Route

HF is a shortcut for Server.HandleFunc.

func (*Server) HFA added in v1.1.0

func (s *Server) HFA(path string, f http.HandlerFunc, roles ...UserRole) *mux.Route

HFA is a shortcut for Server.HandleFuncWithAuth.

func (*Server) HTTPAddress

func (s *Server) HTTPAddress() string

HTTPAddress returns the address the HTTP server is listening on. Returns an empty string if the HTTP server is not running or not configured.

func (*Server) HTTPSAddress

func (s *Server) HTTPSAddress() string

HTTPSAddress returns the address the HTTPS server is listening on. Returns an empty string if the HTTPS server is not running or not configured.

func (*Server) Handle

func (s *Server) Handle(path string, h http.Handler, methods ...string) *mux.Route

Handle registers a new route with the provided path, http.Handler and methods. It returns a pointer to the created mux.Route to set additional settings to the route.

func (*Server) HandleFunc

func (s *Server) HandleFunc(path string, f http.HandlerFunc, methods ...string) *mux.Route

HandleFunc registers a new route with the provided path, http.HandlerFunc and methods. It returns a pointer to the created mux.Route to set additional settings to the route.

func (*Server) HandleFuncWithAuth added in v1.1.0

func (s *Server) HandleFuncWithAuth(path string, f http.HandlerFunc, roles ...UserRole) *mux.Route

HandleFuncWithAuth registers a new route with the provided path, http.HandlerFunc and methods. It adds auth middleware to the route with the provided roles. It returns a pointer to the created mux.Route to set additional settings to the route.

func (*Server) HandleWithAuth added in v1.1.0

func (s *Server) HandleWithAuth(path string, h http.Handler, roles ...UserRole) *mux.Route

HandleWithAuth registers a new route with the provided path, http.Handler and methods. It adds auth middleware to the route with the provided roles. It returns a pointer to the created mux.Route to set additional settings to the route.

func (*Server) IsAuthEnabled added in v1.1.0

func (s *Server) IsAuthEnabled() bool

IsAuthEnabled returns true if auth is enabled.

func (*Server) IsHTTP added in v1.1.0

func (s *Server) IsHTTP() bool

IsHTTP returns true if HTTP is enabled.

func (*Server) IsTLS added in v1.1.0

func (s *Server) IsTLS() bool

IsTLS returns true if TLS is enabled.

func (*Server) R added in v1.1.0

func (s *Server) R(path ...string) *mux.Router

R is a shortcut for Server.Router.

func (*Server) Router

func (s *Server) Router(path ...string) *mux.Router

Router returns mux.Router, it may be useful if you want to work with router manually. It accepts a path to set as a base path for the router.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown gracefully shutdowns HTTP and HTTPS servers.

func (*Server) Start

func (s *Server) Start(httpAddr, httpsAddr string) error

Start starts the server. It takes two parameters: httpAddr and httpsAddr - addresses to listen for HTTP and HTTPS. It returns an error if there was an error starting either of the servers.

func (*Server) StartHTTP

func (s *Server) StartHTTP(address string) error

StartHTTP starts an HTTP server on the provided address. It returns an error if the server cannot be started or address is invalid.

func (*Server) StartHTTPS

func (s *Server) StartHTTPS(address string) error

StartHTTPS starts an HTTPS server on the provided address. It returns an error if the server cannot be started, address is invalid or no certificate is provided in config.

func (*Server) StartWithShutdown

func (s *Server) StartWithShutdown(ctx context.Context, httpAddr, httpsAddr string) error

StartWithShutdown starts HTTP and HTTPS servers and shutdowns its when the context is closed.

func (*Server) StartWithShutdownHTTP

func (s *Server) StartWithShutdownHTTP(ctx context.Context, address string) error

StartWithShutdownHTTP starts the HTTP server and shutdowns it when the context is closed.

func (*Server) StartWithShutdownHTTPS

func (s *Server) StartWithShutdownHTTPS(ctx context.Context, address string) error

StartWithShutdownHTTPS starts the HTTPS server and shutdowns it when the context is closed.

func (*Server) WithAuth added in v1.1.0

func (s *Server) WithAuth(next http.HandlerFunc, roles ...UserRole) http.HandlerFunc

WithAuth adds auth middleware to the router with the provided roles. It returns a pointer to the created mux.Route to set additional settings to the route.

func (*Server) WithBasePath added in v1.1.0

func (s *Server) WithBasePath(path string) *Server

WithBasePath sets the base path for the server's router. It returns the server itself to allow method chaining.

type User added in v1.1.0

type User struct {
	ID                    string     `json:"id" bson:"_id" db:"id"`
	Username              string     `json:"username" bson:"username" db:"username"`
	Roles                 []UserRole `json:"roles" bson:"roles" db:"roles"`
	PasswordHash          string     `json:"password_hash" bson:"password_hash" db:"password_hash"`
	RefreshTokenHash      string     `json:"refresh_token_hash" bson:"refresh_token_hash" db:"refresh_token_hash"`
	RefreshTokenExpiresAt time.Time  `json:"refresh_token_expires_at" bson:"refresh_token_expires_at" db:"refresh_token_expires_at"`
}

User represents a user entity in the system.

type UserContextKey added in v1.1.0

type UserContextKey struct{}

type UserDiff added in v1.1.0

type UserDiff struct {
	Username              *string     `json:"username,omitempty" bson:"username,omitempty" db:"username,omitempty"`
	Roles                 *[]UserRole `json:"roles,omitempty" bson:"roles,omitempty" db:"roles,omitempty"`
	PasswordHash          *string     `json:"password_hash,omitempty" bson:"password_hash,omitempty" db:"password_hash,omitempty"`
	RefreshTokenHash      *string     `json:"refresh_token_hash,omitempty" bson:"refresh_token_hash,omitempty" db:"refresh_token_hash,omitempty"`
	RefreshTokenExpiresAt *time.Time  `json:"refresh_token_expires_at,omitempty" bson:"refresh_token_expires_at,omitempty" db:"refresh_token_expires_at,omitempty"`
}

type UserLoginRequest added in v1.1.0

type UserLoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

UserLoginRequest represents the request body for user login and registration.

func (UserLoginRequest) Validate added in v1.1.0

func (req UserLoginRequest) Validate() error

Validate checks if the UserLoginRequest is valid.

type UserLoginResponse added in v1.1.0

type UserLoginResponse struct {
	ID          string     `json:"id"`
	Username    string     `json:"username"`
	Roles       []UserRole `json:"roles"`
	AccessToken string     `json:"accessToken,omitempty"`
}

UserLoginResponse represents the response body for successful user login or registration.

type UserRole added in v1.1.0

type UserRole string

UserRole represents a role assigned to a user. It's defined as a string type for easy JSON marshaling/unmarshaling.

type UserUpdateRequest added in v1.1.0

type UserUpdateRequest struct {
	ID       string      `json:"id"`
	Username *string     `json:"username,omitempty"`
	Roles    *[]UserRole `json:"roles,omitempty"`
	Password *string     `json:"password,omitempty"`
}

UserUpdateRequest represents the request body for updating user information.

func (UserUpdateRequest) Validate added in v1.1.0

func (req UserUpdateRequest) Validate() error

Validate checks if the UserUpdateRequest is valid.

Jump to

Keyboard shortcuts

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