Skip to content

📝 [Proposal]: Support for Application State Management #3077

Open
@gaby

Description

@gaby

Feature Proposal Description

This proposal aims to introduce Application State Management feature in Fiber to enable the sharing of stateful data across middleware and request handlers efficiently. This is a feature supported in other language frameworks for example: Starlette and FastAPI.

  • Introduce App State Management: Implement a state management system that allows storing and accessing application-wide state.
  • Middleware and Handler Integration: Ensure seamless integration with existing middleware and request handlers.
  • Ease of Use: Provide a simple and intuitive API for developers to interact with the application state.
  • Performance: Ensure that the state management system does not compromise the performance of Fiber.

Sources:

Alignment with Express API

In fiber these proposal is similar to ctx.Locals but applies to the whole application. Resources stored in the state can be accessed by multiple handlers, middlewares, etc.

In Express.js it's similar to app.locals, but in express the values can only be used when rendering templates.

HTTP RFC Standards Compliance

N/a

API Stability

API Methods

  • Set: Set a key-value pair in the application state.
    • What do we do if the Key already exists?
    • Do we add MustSet, to panic if key already exists?
  • Get: Retrieve a value by key from the application state.
  • MustGet: Retrieve a value by key from the application state, panic if not found.
  • Delete: Remove a key-value pair from the application state.
    • This probably requires a mutex.
  • Exists: Check if a key exists in the application state.

We could also add specific Get functions for specific common types: int, string, float, etc. For example, for getting a string from the app.State:

func (s *State) GetString(key string) (string, bool) {
	value, exists := s.state[key]
	if !exists {
		return "", false
	}
	str, ok := value.(string)
	return str, ok
}

It would be the responsibility of the developer to call to appropriate function.

Feature Examples

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

    // Create and set the database client
    connString := "postgres://username:password@localhost:5432/database_name"
    conn, _ := pgx.Connect(context.Background(), connString)
    defer conn.Close(context.Background())

    // Store DB client in App State
    app.State.Set("db", conn)

    app.Get("/", func(c *fiber.Ctx) error {
        // Access the database connection from the AppState
        db, exists := app.State.Get("db")
        if !exists {
            return c.Status(fiber.StatusInternalServerError).SendString("Database connection not found")
        }

        // Use the database connection
        pgxConn := db.(*pgx.Conn)
        var greeting string
        err := pgxConn.QueryRow(context.Background(), "SELECT 'Hello, world!'").Scan(&greeting)
        if err != nil {
            return c.Status(fiber.StatusInternalServerError).SendString("Failed to execute query")
        }
        return c.SendString(greeting)
    })

    app.Listen(":3000")
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have searched for existing issues that describe my proposal before opening this one.
  • I understand that a proposal that does not meet these guidelines may be closed without explanation.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status

      Todo

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions