API: Guantr.prototype.can
The can
method checks if a specific action is permitted on a given resource, according to the rules defined in the Guantr instance. It considers both allow
and deny
rules, including any applicable conditions based on the resource instance and context.
Signature
ts
interface Guantr<Meta, Context> {
can(
action: string, // Or specific action type from Meta
resource: string | [resourceKey: string, resourceInstance: object] // Or typed resource key/instance from Meta
): Promise<boolean>;
}
Parameters
action
: (string
) The action being attempted (e.g.,'read'
,'update'
).resource
: (string
|[string, object]
) The resource being acted upon.- If a
string
(e.g.,'post'
) is provided, it checks rules defined for the general resource type without evaluating instance-specific conditions. - If a tuple
[resourceKey: string, resourceInstance: object]
(e.g.,['post', { id: 1, status: 'draft' }]
) is provided, it checks rules for theresourceKey
and evaluates any conditions against the properties of theresourceInstance
and the current context.
- If a
Returns
Promise<boolean>
: A promise that resolves to:true
if the action is allowed (at least one matchingallow
rule exists and no matchingdeny
rule exists).false
if the action is denied (either no matchingallow
rule exists, or a matchingdeny
rule overrides anyallow
rule).
How it Works
- Retrieves all rules relevant to the given
action
andresource
key usingqueryRules
from the storage adapter. - If a
resourceInstance
is provided, it evaluates thecondition
of each relevant rule against the instance's properties and the current context (obtained viagetContext
). - Determines the outcome: Permission is granted (
true
) if there's at least one applicableallow
rule and no applicabledeny
rules. Otherwise, permission is denied (false
).
Examples
ts
// Assume guantr instance is initialized and rules are set:
// allow('read', 'article');
// deny('read', ['article', { status: ['eq', 'archived'] }]);
// allow('edit', ['article', { ownerId: ['eq', '$ctx.userId'] }]);
const activeArticle = { id: 1, status: 'published', ownerId: 'user-123' };
const archivedArticle = { id: 2, status: 'archived', ownerId: 'user-123' };
const someoneElsesArticle = { id: 3, status: 'published', ownerId: 'user-456' };
// Assume current context userId is 'user-123'
// Check general read permission (doesn't evaluate conditions)
const canReadType = await guantr.can('read', 'article');
// -> true (because the general 'allow read article' rule exists)
// Check read permission on specific instances
const canReadActive = await guantr.can('read', ['article', activeArticle]);
// -> true (general 'allow' applies, 'deny' condition doesn't match)
const canReadArchived = await guantr.can('read', ['article', archivedArticle]);
// -> false (general 'allow' applies, but 'deny' condition *does* match)
// Check edit permission (requires context and instance properties)
const canEditOwn = await guantr.can('edit', ['article', activeArticle]);
// -> true (condition ownerId === $ctx.userId matches)
const canEditElse = await guantr.can('edit', ['article', someoneElsesArticle]);
// -> false (condition ownerId === $ctx.userId does not match)