The requireApproval
Pattern
The core feature of OK!Gotcha is the ability to wrap functions with approval requirements. This is done using the requireApproval
decorator (Python) or higher-order function (TypeScript), which transforms regular functions into approval-gated functions.
import { OkGotcha } from '@okgotcha/sdk';
const ok = OkGotcha();
// Original function
const transferFunds = async (fromAccount: string, toAccount: string, amount: number): Promise<boolean> => {
// Transfer implementation
return true;
};
// Approval-gated function
const secureTransferFunds = ok.requireApproval({
title: "Fund Transfer",
description: "Transfer funds between accounts",
approvers: ["finance-team"]
})(transferFunds);
import { OkGotcha } from '@okgotcha/sdk';
const ok = OkGotcha();
// Original function
const transferFunds = async (fromAccount: string, toAccount: string, amount: number): Promise<boolean> => {
// Transfer implementation
return true;
};
// Approval-gated function
const secureTransferFunds = ok.requireApproval({
title: "Fund Transfer",
description: "Transfer funds between accounts",
approvers: ["finance-team"]
})(transferFunds);
from okgotcha import OkGotcha
ok = OkGotcha()
// Using decorator syntax
@ok.require_approval(
title="Fund Transfer",
description="Transfer funds between accounts",
approvers=["finance-team"]
)
def transfer_funds(from_account: str, to_account: str, amount: float) -> bool:
# Transfer implementation
return True
How It Works
When a function is wrapped with requireApproval
:
- Calling the function creates an approval request instead of executing immediately
- The function’s parameters are captured and serialized
- Approvers are notified through configured channels
- The function remains pending until approved or rejected
- Upon approval, the original function executes with the captured parameters
- Results are returned to the original caller (if using await/async patterns)
OK!Gotcha handles all the complexities of managing approval state, notifications, and execution flow, allowing you to focus on your business logic.
Approval Configuration Options
The requireApproval
function accepts a configuration object with the following properties:
A short, descriptive title for the approval request.
A detailed description of what the approval request is for.
An array of approver IDs or teams who can approve or reject the request.
Time in seconds until the approval request expires (defaults to 24 hours).
Minimum number of approvals required (defaults to 1).
Additional custom data to store with the approval request.
Advanced Usage
Conditional Approval Requirements
You can dynamically determine if approval is required based on the function parameters:
const transferFunds = ok.requireApprovalIf({
title: "High-Value Fund Transfer",
description: "Transfer of funds exceeding $10,000",
approvers: ["finance-team", "security-team"],
condition: (fromAccount, toAccount, amount) => amount > 10000
})(async (fromAccount, toAccount, amount) => {
// Transfer implementation
return true;
});
const transferFunds = ok.requireApprovalIf({
title: "High-Value Fund Transfer",
description: "Transfer of funds exceeding $10,000",
approvers: ["finance-team", "security-team"],
condition: (fromAccount, toAccount, amount) => amount > 10000
})(async (fromAccount, toAccount, amount) => {
// Transfer implementation
return true;
});
@ok.require_approval_if(
title="High-Value Fund Transfer",
description="Transfer of funds exceeding $10,000",
approvers=["finance-team", "security-team"],
condition=lambda from_account, to_account, amount: amount > 10000
)
def transfer_funds(from_account: str, to_account: str, amount: float) -> bool:
# Transfer implementation
return True
Custom Approval Handlers
You can provide custom logic for handling approvals with the onApproved
and onRejected
callbacks:
const secureAction = ok.requireApproval({
title: "Sensitive Action",
description: "Perform a sensitive operation",
approvers: ["security-team"],
onApproved: (result) => {
// Custom logic when approved
logAudit("Action approved and executed successfully");
return result;
},
onRejected: (reason) => {
// Custom logic when rejected
notifyAdmin(`Action rejected: ${reason}`);
throw new Error(`Action rejected: ${reason}`);
}
})(performSensitiveAction);
Next Steps