fiber/docs/middleware/idempotency.md
RW ab7f949382
📒 docs: Idempotency add more detailed description for next method (#3443)
* add more detailed description for next method
2025-05-12 14:59:42 +02:00

108 lines
4.8 KiB
Markdown

---
id: idempotency
---
# Idempotency
Idempotency middleware for [Fiber](https://github.com/gofiber/fiber) allows for fault-tolerant APIs where duplicate requests—for example due to networking issues on the client-side — do not erroneously cause the same action to be performed multiple times on the server-side.
Refer to [IETF RFC 7231 §4.2.2](https://tools.ietf.org/html/rfc7231#section-4.2.2) for definitions of safe and idempotent HTTP methods.
## HTTP Method Categories
* **Safe Methods** (do not modify server state): `GET`, `HEAD`, `OPTIONS`, `TRACE`.
* **Idempotent Methods** (multiple identical requests have the same effect as a single one): all safe methods **plus** `PUT` and `DELETE`.
> According to the RFC, safe methods are guaranteed not to change server state, while idempotent methods may change state but make identical requests safe to repeat.
## Signatures
```go
func New(config ...Config) fiber.Handler
func IsFromCache(c fiber.Ctx) bool
func WasPutToCache(c fiber.Ctx) bool
```
## Examples
Import the middleware package that is part of the Fiber web framework
```go
import (
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/idempotency"
)
```
After you initiate your Fiber app, you can configure the middleware:
### Default Config (Skip **Safe** Methods)
By default, the `Next` function skips middleware for safe methods only:
```go
app.Use(idempotency.New())
```
### Skip **Idempotent** Methods Instead
If you prefer to skip middleware on all idempotent methods (including `PUT`, `DELETE`), override `Next`:
```go
app.Use(idempotency.New(idempotency.Config{
Next: func(c fiber.Ctx) bool {
// Skip middleware for idempotent methods (safe + PUT, DELETE)
return fiber.IsMethodIdempotent(c.Method())
},
}))
```
### Custom Config
```go
app.Use(idempotency.New(idempotency.Config{
Lifetime: 42 * time.Minute,
// ...
}))
```
## Config
| Property | Type | Description | Default |
|:--------------------|:-----------------------|:----------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------|
| Next | `func(fiber.Ctx) bool` | Function to skip this middleware when returning `true`. Choose between `IsMethodSafe` or `IsMethodIdempotent` based on RFC definitions. | `func(c fiber.Ctx) bool { return fiber.IsMethodSafe(c.Method()) }` |
| Lifetime | `time.Duration` | Maximum lifetime of an idempotency key. | `30 * time.Minute` |
| KeyHeader | `string` | Header name containing the idempotency key. | `"X-Idempotency-Key"` |
| KeyHeaderValidate | `func(string) error` | Function to validate idempotency header syntax (e.g., UUID). | UUID length check (`36` characters) |
| KeepResponseHeaders | `[]string` | List of headers to preserve from original response. | `nil` (keep all headers) |
| Lock | `Locker` | Locks an idempotency key to prevent race conditions. | In-memory locker |
| Storage | `fiber.Storage` | Stores response data by idempotency key. | In-memory storage |
## Default Config Values
```go
var ConfigDefault = Config{
Next: func(c fiber.Ctx) bool {
// Skip middleware for safe methods per RFC 7231 §4.2.2
return fiber.IsMethodSafe(c.Method())
},
Lifetime: 30 * time.Minute,
KeyHeader: "X-Idempotency-Key",
KeyHeaderValidate: func(k string) error {
if l, wl := len(k), 36; l != wl { // UUID length is 36 chars
return fmt.Errorf("%w: invalid length: %d != %d", ErrInvalidIdempotencyKey, l, wl)
}
return nil
},
KeepResponseHeaders: nil,
Lock: nil, // Set in configDefault so we don't allocate data here.
Storage: nil, // Set in configDefault so we don't allocate data here.
}
```