Optimistic Locking
OptimisticLockMiddleware enforces version preconditions (If-Match or request param).
Minimal example
use BetterRoute\Middleware\Write\CallbackOptimisticLockVersionResolver;
use BetterRoute\Middleware\Write\OptimisticLockMiddleware;
$versionResolver = new CallbackOptimisticLockVersionResolver(
static function ($context): string|int|null {
// Resolve current version from DB/entity
return 'v12';
}
);
$optimisticLock = new OptimisticLockMiddleware(
versionResolver: $versionResolver,
required: true,
headerName: 'if-match',
paramName: 'version'
);
Behavior
- missing expected version and
required=true->412 precondition_required - missing current version ->
409 version_unavailable - mismatch ->
412 optimistic_lock_failed - match -> passes and stores
optimisticLockattribute in context
Also accepts wildcard expected version: If-Match: *.
Common mistakes
- Not returning deterministic current version from resolver
- Using stale versions from cache for write checks
- Skipping lock on endpoints with concurrent edits
Validation checklist
- quoted ETag forms normalize correctly
- mismatch includes expected/current in error details
- successful request has
optimisticLockcontext attributes