github.com/gofiber/fiber/v2@v2.47.0/middleware/idempotency/config.go (about)

     1  package idempotency
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/gofiber/fiber/v2"
     9  	"github.com/gofiber/fiber/v2/internal/storage/memory"
    10  )
    11  
    12  var ErrInvalidIdempotencyKey = errors.New("invalid idempotency key")
    13  
    14  // Config defines the config for middleware.
    15  type Config struct {
    16  	// Next defines a function to skip this middleware when returned true.
    17  	//
    18  	// Optional. Default: a function which skips the middleware on safe HTTP request method.
    19  	Next func(c *fiber.Ctx) bool
    20  
    21  	// Lifetime is the maximum lifetime of an idempotency key.
    22  	//
    23  	// Optional. Default: 30 * time.Minute
    24  	Lifetime time.Duration
    25  
    26  	// KeyHeader is the name of the header that contains the idempotency key.
    27  	//
    28  	// Optional. Default: X-Idempotency-Key
    29  	KeyHeader string
    30  	// KeyHeaderValidate defines a function to validate the syntax of the idempotency header.
    31  	//
    32  	// Optional. Default: a function which ensures the header is 36 characters long (the size of an UUID).
    33  	KeyHeaderValidate func(string) error
    34  
    35  	// KeepResponseHeaders is a list of headers that should be kept from the original response.
    36  	//
    37  	// Optional. Default: nil (to keep all headers)
    38  	KeepResponseHeaders []string
    39  
    40  	// Lock locks an idempotency key.
    41  	//
    42  	// Optional. Default: an in-memory locker for this process only.
    43  	Lock Locker
    44  
    45  	// Storage stores response data by idempotency key.
    46  	//
    47  	// Optional. Default: an in-memory storage for this process only.
    48  	Storage fiber.Storage
    49  }
    50  
    51  // ConfigDefault is the default config
    52  var ConfigDefault = Config{
    53  	Next: func(c *fiber.Ctx) bool {
    54  		// Skip middleware if the request was done using a safe HTTP method
    55  		return fiber.IsMethodSafe(c.Method())
    56  	},
    57  
    58  	Lifetime: 30 * time.Minute,
    59  
    60  	KeyHeader: "X-Idempotency-Key",
    61  	KeyHeaderValidate: func(k string) error {
    62  		if l, wl := len(k), 36; l != wl { // UUID length is 36 chars
    63  			return fmt.Errorf("%w: invalid length: %d != %d", ErrInvalidIdempotencyKey, l, wl)
    64  		}
    65  
    66  		return nil
    67  	},
    68  
    69  	KeepResponseHeaders: nil,
    70  
    71  	Lock: nil, // Set in configDefault so we don't allocate data here.
    72  
    73  	Storage: nil, // Set in configDefault so we don't allocate data here.
    74  }
    75  
    76  // Helper function to set default values
    77  func configDefault(config ...Config) Config {
    78  	// Return default config if nothing provided
    79  	if len(config) < 1 {
    80  		return ConfigDefault
    81  	}
    82  
    83  	// Override default config
    84  	cfg := config[0]
    85  
    86  	// Set default values
    87  
    88  	if cfg.Next == nil {
    89  		cfg.Next = ConfigDefault.Next
    90  	}
    91  
    92  	if cfg.Lifetime.Nanoseconds() == 0 {
    93  		cfg.Lifetime = ConfigDefault.Lifetime
    94  	}
    95  
    96  	if cfg.KeyHeader == "" {
    97  		cfg.KeyHeader = ConfigDefault.KeyHeader
    98  	}
    99  	if cfg.KeyHeaderValidate == nil {
   100  		cfg.KeyHeaderValidate = ConfigDefault.KeyHeaderValidate
   101  	}
   102  
   103  	if cfg.KeepResponseHeaders != nil && len(cfg.KeepResponseHeaders) == 0 {
   104  		cfg.KeepResponseHeaders = ConfigDefault.KeepResponseHeaders
   105  	}
   106  
   107  	if cfg.Lock == nil {
   108  		cfg.Lock = NewMemoryLock()
   109  	}
   110  
   111  	if cfg.Storage == nil {
   112  		cfg.Storage = memory.New(memory.Config{
   113  			GCInterval: cfg.Lifetime / 2, // Half the lifetime interval
   114  		})
   115  	}
   116  
   117  	return cfg
   118  }