Skip to main content
Version: Next

๐Ÿ—‚๏ธ State Management

The State Management provides a global keyโ€“value store for managing application dependencies and runtime data. This store is shared across the entire application and remains consistent between requests. It is implemented using Goโ€™s sync.Map to ensure safe concurrent access.

State Typeโ€‹

State is a keyโ€“value store built on top of sync.Map. It allows storage and retrieval of dependencies and configurations in a Fiber application as well as threadโ€“safe access to runtime data.

Definitionโ€‹

// State is a keyโ€“value store for Fiber's app, used as a global storage for the app's dependencies.
// It is a threadโ€“safe implementation of a map[string]any, using sync.Map.
type State struct {
dependencies sync.Map
}

Methods on Stateโ€‹

Setโ€‹

Set adds or updates a keyโ€“value pair in the State.

// Set adds or updates a keyโ€“value pair in the State.
func (s *State) Set(key string, value any)

Usage Example:

app.State().Set("appName", "My Fiber App")

Getโ€‹

Get retrieves a value from the State.

Signature
func (s *State) Get(key string) (any, bool)

Usage Example:

value, ok := app.State().Get("appName")
if ok {
fmt.Println("App Name:", value)
}

MustGetโ€‹

MustGet retrieves a value from the State and panics if the key is not found.

Signature
func (s *State) MustGet(key string) any

Usage Example:

appName := app.State().MustGet("appName")
fmt.Println("App Name:", appName)

Hasโ€‹

Has checks if a key exists in the State.

Signature
func (s *State) Has(key string) bool

Usage Example:

if app.State().Has("appName") {
fmt.Println("App Name is set.")
}

Deleteโ€‹

Delete removes a keyโ€“value pair from the State.

Signature
func (s *State) Delete(key string)

Usage Example:

app.State().Delete("obsoleteKey")

Resetโ€‹

Reset removes all keys from the State.

Signature
func (s *State) Reset()

Usage Example:

app.State().Reset()

Keysโ€‹

Keys returns a slice containing all keys present in the State.

Signature
func (s *State) Keys() []string

Usage Example:

keys := app.State().Keys()
fmt.Println("State Keys:", keys)

Lenโ€‹

Len returns the number of keys in the State.

// Len returns the number of keys in the State.
func (s *State) Len() int

Usage Example:

fmt.Printf("Total State Entries: %d\n", app.State().Len())

GetStringโ€‹

GetString retrieves a string value from the State. It returns the string and a boolean indicating a successful type assertion.

Signature
func (s *State) GetString(key string) (string, bool)

Usage Example:

if appName, ok := app.State().GetString("appName"); ok {
fmt.Println("App Name:", appName)
}

GetIntโ€‹

GetInt retrieves an integer value from the State. It returns the int and a boolean indicating a successful type assertion.

Signature
func (s *State) GetInt(key string) (int, bool)

Usage Example:

if count, ok := app.State().GetInt("userCount"); ok {
fmt.Printf("User Count: %d\n", count)
}

GetBoolโ€‹

GetBool retrieves a boolean value from the State. It returns the bool and a boolean indicating a successful type assertion.

Signature
func (s *State) GetBool(key string) (value, bool)

Usage Example:

if debug, ok := app.State().GetBool("debugMode"); ok {
fmt.Printf("Debug Mode: %v\n", debug)
}

GetFloat64โ€‹

GetFloat64 retrieves a float64 value from the State. It returns the float64 and a boolean indicating a successful type assertion.

Signature
func (s *State) GetFloat64(key string) (float64, bool)

Usage Example:

Signature
if ratio, ok := app.State().GetFloat64("scalingFactor"); ok {
fmt.Printf("Scaling Factor: %f\n", ratio)
}

GetUintโ€‹

GetUint retrieves a uint value from the State.

Signature
func (s *State) GetUint(key string) (uint, bool)

Usage Example:

if val, ok := app.State().GetUint("maxConnections"); ok {
fmt.Printf("Max Connections: %d\n", val)
}

GetInt8โ€‹

GetInt8 retrieves an int8 value from the State.

Signature
func (s *State) GetInt8(key string) (int8, bool)

Usage Example:

if val, ok := app.State().GetInt8("threshold"); ok {
fmt.Printf("Threshold: %d\n", val)
}

GetInt16โ€‹

GetInt16 retrieves an int16 value from the State.

Signature
func (s *State) GetInt16(key string) (int16, bool)

Usage Example:

if val, ok := app.State().GetInt16("minValue"); ok {
fmt.Printf("Minimum Value: %d\n", val)
}

GetInt32โ€‹

GetInt32 retrieves an int32 value from the State.

Signature
func (s *State) GetInt32(key string) (int32, bool)

Usage Example:

if val, ok := app.State().GetInt32("portNumber"); ok {
fmt.Printf("Port Number: %d\n", val)
}

GetInt64โ€‹

GetInt64 retrieves an int64 value from the State.

Signature
func (s *State) GetInt64(key string) (int64, bool)

Usage Example:

if val, ok := app.State().GetInt64("fileSize"); ok {
fmt.Printf("File Size: %d\n", val)
}

GetUint8โ€‹

GetUint8 retrieves a uint8 value from the State.

Signature
func (s *State) GetUint8(key string) (uint8, bool)

Usage Example:

if val, ok := app.State().GetUint8("byteValue"); ok {
fmt.Printf("Byte Value: %d\n", val)
}

GetUint16โ€‹

GetUint16 retrieves a uint16 value from the State.

Signature
func (s *State) GetUint16(key string) (uint16, bool)

Usage Example:

if val, ok := app.State().GetUint16("limit"); ok {
fmt.Printf("Limit: %d\n", val)
}

GetUint32โ€‹

GetUint32 retrieves a uint32 value from the State.

Signature
func (s *State) GetUint32(key string) (uint32, bool)

Usage Example:

if val, ok := app.State().GetUint32("timeout"); ok {
fmt.Printf("Timeout: %d\n", val)
}

GetUint64โ€‹

GetUint64 retrieves a uint64 value from the State.

Signature
func (s *State) GetUint64(key string) (uint64, bool)

Usage Example:

if val, ok := app.State().GetUint64("maxSize"); ok {
fmt.Printf("Max Size: %d\n", val)
}

GetUintptrโ€‹

GetUintptr retrieves a uintptr value from the State.

Signature
func (s *State) GetUintptr(key string) (uintptr, bool)

Usage Example:

if val, ok := app.State().GetUintptr("pointerValue"); ok {
fmt.Printf("Pointer Value: %d\n", val)
}

GetFloat32โ€‹

GetFloat32 retrieves a float32 value from the State.

Signature
func (s *State) GetFloat32(key string) (float32, bool)

Usage Example:

if val, ok := app.State().GetFloat32("scalingFactor32"); ok {
fmt.Printf("Scaling Factor (float32): %f\n", val)
}

GetComplex64โ€‹

GetComplex64 retrieves a complex64 value from the State.

Signature
func (s *State) GetComplex64(key string) (complex64, bool)

Usage Example:

if val, ok := app.State().GetComplex64("complexVal"); ok {
fmt.Printf("Complex Value (complex64): %v\n", val)
}

GetComplex128โ€‹

GetComplex128 retrieves a complex128 value from the State.

Signature
func (s *State) GetComplex128(key string) (complex128, bool)

Usage Example:

if val, ok := app.State().GetComplex128("complexVal128"); ok {
fmt.Printf("Complex Value (complex128): %v\n", val)
}

Generic Functionsโ€‹

Fiber provides generic functions to retrieve state values with type safety and fallback options.

GetStateโ€‹

GetState retrieves a value from the State and casts it to the desired type. It returns the cast value and a boolean indicating if the cast was successful.

Signature
func GetState[T any](s *State, key string) (T, bool)

Usage Example:

// Retrieve an integer value safely.
userCount, ok := GetState[int](app.State(), "userCount")
if ok {
fmt.Printf("User Count: %d\n", userCount)
}

MustGetStateโ€‹

MustGetState retrieves a value from the State and casts it to the desired type. It panics if the key is not found or if the type assertion fails.

Signature
func MustGetState[T any](s *State, key string) T

Usage Example:

// Retrieve the value or panic if it is not present.
config := MustGetState[string](app.State(), "configFile")
fmt.Println("Config File:", config)

GetStateWithDefaultโ€‹

GetStateWithDefault retrieves a value from the State, casting it to the desired type. If the key is not present, it returns the provided default value.

Signature
func GetStateWithDefault[T any](s *State, key string, defaultVal T) T

Usage Example:

// Retrieve a value with a default fallback.
requestCount := GetStateWithDefault[int](app.State(), "requestCount", 0)
fmt.Printf("Request Count: %d\n", requestCount)

Comprehensive Examplesโ€‹

Example: Request Counterโ€‹

This example demonstrates how to track the number of requests using the State.

package main

import (
"fmt"

"github.com/gofiber/fiber/v3"
)

func main() {
app := fiber.New()

// Initialize state with a counter.
app.State().Set("requestCount", 0)

// Middleware: Increase counter for every request.
app.Use(func(c fiber.Ctx) error {
count, _ := c.App().State().GetInt("requestCount")
app.State().Set("requestCount", count+1)
return c.Next()
})

app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello World!")
})

app.Get("/stats", func(c fiber.Ctx) error {
count, _ := c.App().State().Get("requestCount")
return c.SendString(fmt.Sprintf("Total requests: %d", count))
})

app.Listen(":3000")
}

Example: Environmentโ€“Specific Configurationโ€‹

This example shows how to configure different settings based on the environment.

package main

import (
"os"

"github.com/gofiber/fiber/v3"
)

func main() {
app := fiber.New()

// Determine environment.
environment := os.Getenv("ENV")
if environment == "" {
environment = "development"
}
app.State().Set("environment", environment)

// Set environment-specific configurations.
if environment == "development" {
app.State().Set("apiUrl", "http://localhost:8080/api")
app.State().Set("debug", true)
} else {
app.State().Set("apiUrl", "https://api.production.com")
app.State().Set("debug", false)
}

app.Get("/config", func(c fiber.Ctx) error {
config := map[string]any{
"environment": environment,
"apiUrl": fiber.GetStateWithDefault(c.App().State(), "apiUrl", ""),
"debug": fiber.GetStateWithDefault(c.App().State(), "debug", false),
}
return c.JSON(config)
})

app.Listen(":3000")
}

Example: Dependency Injection with State Managementโ€‹

This example demonstrates how to use the State for dependency injection in a Fiber application.

package main

import (
"context"
"fmt"
"log"

"github.com/gofiber/fiber/v3"
"github.com/redis/go-redis/v9"
)

type User struct {
ID int `query:"id"`
Name string `query:"name"`
Email string `query:"email"`
}

func main() {
app := fiber.New()
ctx := context.Background()

// Initialize Redis client.
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})

// Check the Redis connection.
if err := rdb.Ping(ctx).Err(); err != nil {
log.Fatalf("Could not connect to Redis: %v", err)
}

// Inject the Redis client into Fiber's State for dependency injection.
app.State().Set("redis", rdb)

app.Get("/user/create", func(c fiber.Ctx) error {
var user User
if err := c.Bind().Query(&user); err != nil {
return c.Status(fiber.StatusBadRequest).SendString(err.Error())
}

// Save the user to the database.
rdb, ok := fiber.GetState[*redis.Client](c.App().State(), "redis")
if !ok {
return c.Status(fiber.StatusInternalServerError).SendString("Redis client not found")
}

// Save the user to the database.
key := fmt.Sprintf("user:%d", user.ID)
err := rdb.HSet(ctx, key, "name", user.Name, "email", user.Email).Err()
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}

return c.JSON(user)
})

app.Get("/user/:id", func(c fiber.Ctx) error {
id := c.Params("id")

rdb, ok := fiber.GetState[*redis.Client](c.App().State(), "redis")
if !ok {
return c.Status(fiber.StatusInternalServerError).SendString("Redis client not found")
}

key := fmt.Sprintf("user:%s", id)
user, err := rdb.HGetAll(ctx, key).Result()
if err == redis.Nil {
return c.Status(fiber.StatusNotFound).SendString("User not found")
} else if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}

return c.JSON(user)
})

app.Listen(":3000")
}