Build powerful targeting rules: segment membership, user attributes, geographic location, custom conditions. Support rule operators (eq, contains, regex). Add rule priority to control evaluation order. By the end, users can target flags with surgical precision.
← Back to Module 03 overviewPOST /flags/:id/rules — create a targeting rule with priority.PATCH /flags/:id/rules/:ruleId — update rule condition or priority.DELETE /flags/:id/rules/:ruleId — delete a rule.eq, ne, contains, regex, gt, lt.Create src/utils/ruleEngine.ts:
import { EvaluationContext } from '../types/flag';
interface Rule {
rule_type: 'segment' | 'user_attribute' | 'percentage';
rule_value: Record;
}
export function evaluateRule(rule: Rule, context: EvaluationContext): boolean {
if (rule.rule_type === 'segment') {
return context.segment === rule.rule_value.segment;
}
if (rule.rule_type === 'user_attribute') {
const attr = rule.rule_value.attribute;
const operator = rule.rule_value.operator; // eq, ne, contains, regex, gt, lt
const expected = rule.rule_value.value;
const actual = context.attributes?.[attr];
if (actual === undefined) return false;
switch (operator) {
case 'eq':
return actual === expected;
case 'ne':
return actual !== expected;
case 'contains':
return String(actual).includes(String(expected));
case 'regex':
return new RegExp(expected).test(String(actual));
case 'gt':
return Number(actual) > Number(expected);
case 'lt':
return Number(actual) < Number(expected);
default:
return false;
}
}
if (rule.rule_type === 'percentage') {
const percentage = rule.rule_value.percentage || 0;
const userId = context.user_id || context.session_id || '';
const hash = hashString(userId);
return hash % 100 < percentage;
}
return false;
}
function hashString(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash);
}