blueprint

package module
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: Oct 18, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

README

blueprint

go-version Release Build Status lint


Documentation: https://oddbit-project.github.io/blueprint/


Blueprint is a modular Go application framework for building web applications and microservices. Starting from v0.8.0, Blueprint features a modular architecture that allows you to import only the components you need, reducing dependencies and improving build times.

Table of Contents

Installation
# Install core framework
go get github.com/oddbit-project/blueprint

# Install specific providers as needed
go get github.com/oddbit-project/blueprint/provider/httpserver
go get github.com/oddbit-project/blueprint/provider/jwtprovider
go get github.com/oddbit-project/blueprint/provider/kafka
go get github.com/oddbit-project/blueprint/provider/pgsql
Using Providers
// Import specific providers
import "github.com/oddbit-project/blueprint/provider/httpserver"
import "github.com/oddbit-project/blueprint/provider/jwtprovider"
import "github.com/oddbit-project/blueprint/provider/kafka"
import "github.com/oddbit-project/blueprint/provider/pgsql"

// Core framework imports work as before
import "github.com/oddbit-project/blueprint"
import "github.com/oddbit-project/blueprint/log"

Features

Blueprint provides:

  • Container-based application lifecycle management
  • Configuration management
  • Structured logging with file rotation
  • HTTP server with comprehensive security features:
    • TLS support with configurable cipher suites
    • CSRF protection with session-based tokens
    • Security headers (CSP, HSTS, XSS protection, etc.)
    • Rate limiting with per-IP and per-endpoint controls
    • Device fingerprinting for security monitoring
    • Cookie-based session management with multiple backends
  • Authentication providers:
    • JWT authentication with symmetric/asymmetric key support
    • Token revocation system
    • HTPasswd file-based authentication
  • Database connectivity (PostgreSQL, SQLite, ClickHouse)
  • Typed generic repositories (dbx) on the injection-safe gohan query builder
  • Message queue integration (Kafka, MQTT)
  • Metrics endpoint for Prometheus monitoring
  • Middleware system with request helpers and utilities

Application example

Applications are executed in a runtime context, instantiated from blueprint.Container. This container holds the main run cycle, and manages the startup/shutdown cycle of the application.

It is possible to register global destructor functions that will be called back in sequence when the application is terminated. To achieve this, any ordered application exit must use blueprint.Shutdown():

(...)
if err := doSomething(); err != nil {
	// perform application shutdown
	blueprint.Shutdown(err)
	os.exit(-1)
}

Simple API application example using blueprint.Container with JWT authentication and security middleware:

package main

import (
  "flag"
  "fmt"
  "github.com/gin-gonic/gin"
  "github.com/oddbit-project/blueprint"
  "github.com/oddbit-project/blueprint/config/provider"
  "github.com/oddbit-project/blueprint/log"
  "github.com/oddbit-project/blueprint/provider/httpserver"
  "github.com/oddbit-project/blueprint/provider/httpserver/auth"
  "github.com/oddbit-project/blueprint/provider/httpserver/response"
  "github.com/oddbit-project/blueprint/provider/jwtprovider"
  "os"
)

const (
  VERSION = "9.9.0"
)

// CliArgs Command-line options
type CliArgs struct {
  ConfigFile  *string
  ShowVersion *bool
}

// Application sample application container
type Application struct {
  *blueprint.Container                    // runnable application container
  args                 *CliArgs           // cli args
  httpServer           *httpserver.Server // our api server
  logger               *log.Logger
  jwtProvider          jwtprovider.JWTProvider // JWT authentication provider
}

// command-line args
var cliArgs = &CliArgs{
  ConfigFile:  flag.String("c", "config/config.json", "Config file"),
  ShowVersion: flag.Bool("version", false, "Show version"),
}

// NewApplication Sample application factory
func NewApplication(args *CliArgs, logger *log.Logger) (*Application, error) {
  cfg, err := provider.NewJsonProvider(*args.ConfigFile)
  if err != nil {
    return nil, err
  }
  if logger == nil {
    logger = log.New("application")
  }
  return &Application{
    Container:   blueprint.NewContainer(cfg),
    args:        args,
    httpServer:  nil,
    logger:      logger,
    jwtProvider: nil,
  }, nil
}

func (a *Application) Build() {
  // assemble internal dependencies of application
  // if some error occurs, generate fatal error & abort execution
  var err error

  // initialize http server
  a.logger.Info("Building Sample Application...")

  // initialize JWT provider from configuration
  jwtConfig := jwtprovider.NewJWTConfig()
  a.AbortFatal(a.Config.GetKey("jwt", jwtConfig))

  // optional - create a revocation manager instance for token revocation
  revocationManager := jwtprovider.NewRevocationManager(jwtprovider.NewMemoryRevocationBackend())

  // create the JWT provider to use with the API server
  a.jwtProvider, err = jwtprovider.NewProvider(jwtConfig, jwtprovider.WithRevocationManager(revocationManager))
  a.AbortFatal(err)

  a.jwtProvider, err = jwtprovider.NewProvider(jwtConfig)
  a.AbortFatal(err)

  // initialize http server config
  httpConfig := httpserver.NewServerConfig()
  // fill parameters from config provider
  a.AbortFatal(a.Config.GetKey("server", httpConfig))

  // Create http server from config
  a.httpServer, err = httpConfig.NewServer(a.logger)
  a.AbortFatal(err)

  // Apply security middleware
  a.httpServer.UseDefaultSecurityHeaders()
  a.httpServer.UseCSRFProtection()
  a.httpServer.UseRateLimiting(60) // 60 requests per minute

  // Create router group
  v1 := a.httpServer.Route().Group("/v1")

  // Public login endpoint
  a.httpServer.Route().POST("/login", func(ctx *gin.Context) {
    // Basic authentication logic (replace with your auth system)
    var loginData struct {
      Username string `json:"username" binding:"required"`
      Password string `json:"password" binding:"required"`
    }

    // bind request params
    if !httpserver.ValidateJSON(ctx, &loginData) {
      // if ValidateJSON() fails, error response was already sent
      return
    }

    // Validate credentials (implement your validation logic)
    if loginData.Username == "demo" && loginData.Password == "password" {
      token, err := a.jwtProvider.GenerateToken("demo", map[string]interface{}{
        "role": "user",
      })
      if err != nil {
        response.Http400(ctx, "Token generation failed")
        return
      }

      response.Success(ctx, gin.H{"token": token})
      return
    }

    response.Http401(ctx)
  })

  // Create JWT auth middleware and enable middleware
  jwtAuth := auth.NewAuthJWT(a.jwtProvider)
  v1.Use(auth.AuthMiddleware(jwtAuth))

  // protected endpoint: /v1/hello
  v1.GET("/hello", func(ctx *gin.Context) {
    token, _ := auth.GetJWTToken(ctx)
    claims, err := a.jwtProvider.ParseToken(token)
    if err != nil {
      response.Http400(ctx, "Token generation failed")
      return
    }

    response.Success(ctx, gin.H{
      "id":   claims.ID,
      "user": claims.Subject,
      "data": claims.Data,
    })
  })

}

func (a *Application) Start() {

  // register http destructor callback
  blueprint.RegisterDestructor(func() error {
    return a.httpServer.Shutdown(blueprint.ShutdownContext())
  })

  // Start  application - http server
  a.Run(func(app interface{}) error {
    go func() {
      a.logger.Infof("Running Sample Application API at http://%s:%d", a.httpServer.Config.Host, a.httpServer.Config.Port)
      a.logger.Infof("Login: POST /login (username: demo, password: password)")
      a.logger.Infof("Protected: GET /v1/hello (requires JWT token)")
      a.AbortFatal(a.httpServer.Start())
    }()
    return nil
  })
}

func main() {
  // config logger
  log.Configure(log.NewDefaultConfig())
  logger := log.New("sample-application")

  flag.Parse()

  if *cliArgs.ShowVersion {
    fmt.Printf("Version: %s\n", VERSION)
    os.Exit(0)
  }

  app, err := NewApplication(cliArgs, logger)
  if err != nil {
    logger.Error(err, "Initialization failed")
    os.Exit(-1)
  }

  // build application
  app.Build()
  // execute application
  app.Start()
}

Example config file sample.json:

{
  "server": {
    "host": "localhost",
    "port": 8080,
    "readTimeout": 30,
    "writeTimeout": 30,
    "debug": true,
    "tlsEnable": false
  },
  "jwt": {
    "signingKey": {
      "password": "your-jwt-secret-key-change-in-production"
    },
    "signingAlgorithm": "HS256",
    "expirationSeconds": 3600,
    "issuer": "sample-application",
    "audience": "api-users",
    "keyID": "default",
    "requireIssuer": true,
    "requireAudience": true,
    "trackUserTokens": false,
    "maxUserSessions": 0,
    "maxTokenSize": 4096
  }
}

Core Framework

Blueprint's base library provides the following components for application development:

Application Lifecycle
  • Container - Application lifecycle management with graceful startup/shutdown
  • Configuration - JSON and environment-based configuration with validation and removed-key checks
  • Logging - Structured logging with file rotation and levels
Database
Security & Cryptography
  • Password Hashing - Argon2id password hashing with timing attack protection
  • PIN Generation - Cryptographically secure PIN generation and comparison
  • Secure Credentials - In-memory credential encryption and key management
  • TLS - TLS/SSL certificate management
Utilities
  • ThreadPool - High-performance worker pool with graceful shutdown
  • BatchWriter - Batched operations with time and size-based flushing
# Core framework includes all these components
go get github.com/oddbit-project/blueprint
Core Usage Example
package main

import (
    "github.com/oddbit-project/blueprint"
    "github.com/oddbit-project/blueprint/config/provider"
    "github.com/oddbit-project/blueprint/log"
    "github.com/oddbit-project/blueprint/db"
)

func main() {
    // Initialize logging
    log.Configure(log.NewDefaultConfig())
    logger := log.New("my-app")
    
    // Load configuration
    cfg, _ := provider.NewJsonProvider("config.json")
    
    // Create application container
    app := blueprint.NewContainer()
    
    // Your application logic here
    logger.Info("Application started")
    
    // Run application with graceful shutdown
    app.Run()
}

Available Providers

Blueprint also includes the following modular providers:

Message Queues & Communication
  • Kafka - Apache Kafka integration with SASL authentication
  • NATS - NATS messaging system integration
  • MQTT - MQTT broker communication
Databases & Storage
  • PostgreSQL - PostgreSQL database integration with connection pooling
  • SQLite - Embedded SQLite database via pure-Go driver (no CGO)
  • ClickHouse - ClickHouse database for analytics workloads
  • S3 - S3-compatible object storage (AWS S3, MinIO, etc.) with Object Lock (WORM) and object versions
  • etcd - Distributed key-value store integration
Web & HTTP
  • HTTP Server - Complete HTTP server with middleware, security, and routing
  • Metrics - Prometheus metrics endpoint
Authentication & Security
Utilities
  • SMTP - Email sending functionality

Each provider is independently versioned and can be imported separately. See the documentation for detailed usage examples.

Security

Please report vulnerabilities privately — see SECURITY.md. Do not open public issues for security problems.

License information

All the custom code is licensed under Apache2 license. Some code pieces were copied or imported from different sources, and have their own licensing info. All the adapted files contain a full copy of their respective license, and all the adaptations are licensed under the original license of the source.

The repository includes code adapted from the following sources:

Argon2Id password hashing (c) Alex Edwards, MIT License

Telegraf TLS plugin (c) InfluxData Inc, MIT License

Threadsafe package (c) Ravishanker Kusuma, MIT License

Documentation

Index

Constants

View Source
const DefaultShutdownTimeout = 5 * time.Second

DefaultShutdownTimeout is the default deadline of ShutdownContext, counted from the start of Shutdown

Variables

This section is empty.

Functions

func GetDestructorManager

func GetDestructorManager() *callstack.CallStack

GetDestructorManager Retrieve callback manager; returns nil after Shutdown

func RegisterDestructor

func RegisterDestructor(fn callstack.CallableFn)

RegisterDestructor Register a function to perform shutdown procedures Calling RegisterDestructor after (or during) Shutdown is a no-op

func SetShutdownTimeout added in v0.16.0

func SetShutdownTimeout(d time.Duration)

SetShutdownTimeout sets the deadline of ShutdownContext, counted from the start of Shutdown; a d of zero or less gives destructors an already expired context. Keep it below the grace period of whatever stops the process (docker stop: 10s), or later destructors are killed before they run. Shutdown does not enforce it: a destructor that does not use ShutdownContext is not interrupted

func Shutdown

func Shutdown(arg error)

Shutdown Shuts down the whole application Only the first call runs the destructors; a call made while they are running returns immediately (or, with a non-nil arg, logs the fatal error and exits without waiting for them)

func ShutdownContext added in v0.16.0

func ShutdownContext() context.Context

ShutdownContext returns the context destructors pass to Shutdown/Stop calls, e.g. server.Shutdown(blueprint.ShutdownContext()); the application context cannot be used for this, as on a signal it is already cancelled when destructors run. Call it from a destructor: elsewhere it may be called before Shutdown has started. During Shutdown it has one deadline, the shutdown timeout counted from the start of Shutdown, shared by all destructors. Before Shutdown it returns context.Background(); after Shutdown, a cancelled context

Types

type Container

type Container struct {
	Config    config.ConfigProvider
	Context   context.Context
	CancelCtx context.CancelFunc
	// contains filtered or unexported fields
}

func NewContainer

func NewContainer(config config.ConfigProvider) *Container

NewContainer create new container runtime with the specified config provider and a new application context

func (*Container) AbortFatal

func (c *Container) AbortFatal(err error)

AbortFatal aborts execution in case of fatal error

func (*Container) Exists added in v0.3.0

func (c *Container) Exists(name string) bool

Exists check if a service is registered

func (*Container) Get added in v0.3.0

func (c *Container) Get(name string) (interface{}, bool)

Get retrieve a service by name

func (*Container) GetContext

func (c *Container) GetContext() context.Context

GetContext helper function to retrieve context

func (*Container) Register added in v0.3.0

func (c *Container) Register(name string, service interface{})

Register a service by name

func (*Container) Run

func (c *Container) Run(mainFn ...RuntimeFn)

Run runs application container mainFn is a collection of non-blocking functions; they will be executed in order. each one will receive the Container object as the parameter: Example:

container.Run(func(a interface{}) error {
	app := a.(*Container)
	app.AbortFatal(nil) // won't abort because arg is nil
	return nil
})

the main loop will wait for an os signal on the 'monitor' channel or for the application context to be canceled; on signal, the application context is canceled first and the registered destructors are then executed via Shutdown(); in both cases the application is terminated by invoking Terminate()

func (*Container) Terminate

func (c *Container) Terminate(err error)

Terminate application execution and exit to operating system

type RuntimeFn

type RuntimeFn func(app interface{}) error

Directories

Path Synopsis
crypt
pin
db
qb
Package dbx provides typed generic repositories on top of gohan, with a database/sql adapter and transaction helper.
Package dbx provides typed generic repositories on top of gohan, with a database/sql adapter and transaction helper.
log
provider
kv
tls
clickhouse module
etcd module
franz module
hmacprovider module
htpasswd module
httpserver module
jwtprovider module
kafka module
metrics module
mqtt module
nats module
pgsql module
prometheus module
redis module
s3 module
smtp module
sqlite module
samples
application command
ch-migrations command
clickhouse command
console command
dbgrid command
dbx-sqlite command
Command dbx-sqlite is a runnable sample for the dbx package: it opens a SQLite database (no external service required), creates a users table, inserts two users through a dbx.Repository, counts them, fetches one by name with GetBy, and runs a Contains search.
Command dbx-sqlite is a runnable sample for the dbx package: it opens a SQLite database (no external service required), creates a users table, inserts two users through a dbx.Repository, counts them, fetches one by name with GetBy, and runs a Contains search.
etcd command
filelogging command
franz command
htpasswd command
http-csrf command
httpserver command
kafka command
metrics command
mqtt command
nats command
nextjs-api-demo command
pgsql command
prometheus command
s3-client command
s3-objectlock command
Command s3-objectlock demonstrates the S3 provider's Object Lock (WORM) features: bucket-level default retention, per-object retention (Governance/Compliance), governance bypass, and legal holds.
Command s3-objectlock demonstrates the S3 provider's Object Lock (WORM) features: bucket-level default retention, per-object retention (Governance/Compliance), governance bypass, and legal holds.
session-example command
sqlite command
types
duration
Package duration provides a JSON-friendly duration type for configuration.
Package duration provides a JSON-friendly duration type for configuration.
jsoncol
Package jsoncol provides JSON[T], a generic database column type that stores T as JSON text: PostgreSQL json/jsonb, or SQLite TEXT.
Package jsoncol provides JSON[T], a generic database column type that stores T as JSON text: PostgreSQL json/jsonb, or SQLite TEXT.
optional
Package optional provides Optional[T], a tri-state value for PATCH-style request bodies, where "field absent", "field explicitly null" and "field set to a value" mean different things:
Package optional provides Optional[T], a tri-state value for PATCH-style request bodies, where "field absent", "field explicitly null" and "field set to a value" mean different things:
threadsafe
* imported from https://github.com/hayageek/threadsafe * (c) Copyright (c) 2024 Ravishanker Kusuma - MIT License * See LICENSE for more details
* imported from https://github.com/hayageek/threadsafe * (c) Copyright (c) 2024 Ravishanker Kusuma - MIT License * See LICENSE for more details
env
fs
str

Jump to

Keyboard shortcuts

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