关于 openfeature
openfeature 是 OpenFeature SDK 集成指南,供需要在应用中实现功能标志的开发者使用。它介绍跨语言的统一 API、提供程序、评估上下文、钩子及测试模式。
主要功能
- 01跨提供程序的统一功能标志 API
- 02布尔、字符串、数值和对象标志评估
- 03评估上下文与钩子
- 04Node.js、Python、Go、Java、Rust 集成
- 05内存提供程序与单元测试模式
适用场景
- 01为应用接入功能标志 SDK
- 02实现 A/B 测试或渐进式发布
- 03为标志评估配置用户定向上下文
- 04使用内存提供程序测试标志逻辑
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ laurigates/ claude-plugins --skill openfeature安装后在 Claude Code 中输入/openfeature确认已加载。
详细介绍
OpenFeature SDK 集成
何时使用此技能
| 在以下情况使用此技能…… | 在以下情况改用相关技能…… |
|---|---|
| 你需要与供应商无关的 OpenFeature SDK API、钩子和评估模式 | 你需要 GO Feature Flag(GOFF)可自托管后端的具体信息——使用 go-feature-flag |
| 你要在不同提供方之间做出选择,或将 OpenFeature 客户端接入应用代码 | 你想从头搭建完整的功能标志技术栈(SDK + 提供方 + CI)——使用 configure-feature-flags |
| 其他技能需要 OpenFeature 语义的权威参考 | 你想在更改任何内容前,检测现有功能标志配置——使用 configure-feature-flags |
与供应商无关的功能标志 SDK,提供跨语言和提供方的标准化 API。用于通过任意功能标志后端实现功能标志、A/B 测试、金丝雀发布或渐进式发布。
何时使用
自动激活条件:
- 用户提到“功能标志”“功能切换”或“功能管理”
- 用户询问 A/B 测试或金丝雀发布
- 用户想要实现渐进式发布
- 项目包含 OpenFeature SDK 依赖项
- 用户提到 OpenFeature、flagd 或与供应商无关的标志
相关技能:
go-feature-flag- GO Feature Flag 提供方的具体信息launchdarkly- LaunchDarkly 提供方集成
核心概念
架构
┌─────────────────────────────────────────────────────────────┐
│ Application Code │
├─────────────────────────────────────────────────────────────┤
│ OpenFeature SDK (API) │
│ ┌─────────────┬──────────────┬─────────────┬─────────────┐ │
│ │ getBool() │ getString() │ getNumber()│ getObject()│ │
│ └─────────────┴──────────────┴─────────────┴─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Provider │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ GO Feature Flag │ flagd │ LaunchDarkly │ Split │ etc │ │
│ └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Flag Source │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ File │ S3 │ GitHub │ API │ ConfigMap │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
关键组件
- API - 用于评估标志的标准化接口
- 提供方 - 特定后端的实现
- 评估上下文 - 用于定向的用户/请求数据
- 钩子 - 用于日志记录、遥测的生命周期扩展
SDK 安装
Node.js(服务端)
# Core SDK
npm install @openfeature/server-sdk
# Providers (choose one)
npm install @openfeature/go-feature-flag-provider # GO Feature Flag
npm install @openfeature/flagd-provider # flagd
npm install @openfeature/in-memory-provider # Testing
Node.js(浏览器/React)
# Web SDK
npm install @openfeature/web-sdk
# React integration
npm install @openfeature/react-sdk
# Web providers
npm install @openfeature/go-feature-flag-web-provider
Python
uv add openfeature-sdk
uv add openfeature-provider-go-feature-flag # GO Feature Flag provider
Go
go get github.com/open-feature/go-sdk
go get github.com/open-feature/go-sdk-contrib/providers/go-feature-flag
Java
<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>1.7.0</version>
</dependency>
Rust
[dependencies]
open-feature = "0.2"
基本用法模式
初始化
// TypeScript/Node.js
import { OpenFeature } from '@openfeature/server-sdk';
import { GoFeatureFlagProvider } from '@openfeature/go-feature-flag-provider';
// Initialize provider
const provider = new GoFeatureFlagProvider({
endpoint: process.env.GOFF_RELAY_URL || 'http://localhost:1031',
});
// Set provider (awaitable for ready state)
await OpenFeature.setProviderAndWait(provider);
// Get client
const client = OpenFeature.getClient('my-app');
标志评估
// Boolean flag
const isEnabled = await client.getBooleanValue('new-feature', false);
// String flag
const buttonColor = await client.getStringValue('button-color', '#000000');
// Number flag
const maxItems = await client.getNumberValue('max-items', 10);
// Object/JSON flag
const config = await client.getObjectValue('feature-config', {});
// With evaluation context
const context = { targetingKey: userId, email: userEmail, groups: ['beta'] };
const isEnabled = await client.getBooleanValue('new-feature', false, context);
评估上下文
// Creating context
const context: EvaluationContext = {
// Required: unique identifier for targeting
targetingKey: user.id,
// Optional: additional attributes for targeting rules
email: user.email,
groups: user.roles,
plan: user.subscription,
// Custom attributes
country: request.geoip.country,
browser: request.headers['user-agent'],
};
// Set global context (applies to all evaluations)
OpenFeature.setContext(context);
// Or per-evaluation context
await client.getBooleanValue('feature', false, context);
钩子
import { Hook, HookContext, EvaluationDetails } from '@openfeature/server-sdk';
// Logging hook
const loggingHook: Hook = {
before: (hookContext: HookContext) => {
console.log(`Evaluating flag: ${hookContext.flagKey}`);
},
after: (hookContext: HookContext, details: EvaluationDetails<unknown>) => {
console.log(`Flag ${hookContext.flagKey} = ${details.value}`);
},
error: (hookContext: HookContext, error: Error) => {
console.error(`Error evaluating ${hookContext.flagKey}:`, error);
},
};
// Register globally
OpenFeature.addHooks(loggingHook);
// Or per-client
client.addHooks(loggingHook);
React 集成
import { OpenFeatureProvider, useFlag, useBooleanFlagValue } from '@openfeature/react-sdk';
import { GoFeatureFlagWebProvider } from '@openfeature/go-feature-flag-web-provider';
// Provider setup
const provider = new GoFeatureFlagWebProvider({
endpoint: import.meta.env.VITE_GOFF_RELAY_URL,
});
function App() {
return (
<OpenFeatureProvider provider={provider}>
<MyComponent />
</OpenFeatureProvider>
);
}
// Using flags in components
function MyComponent() {
// Simple boolean value
const isEnabled = useBooleanFlagValue('new-feature', false);
// Full flag details
const { value, isLoading, error } = useFlag('button-color', '#000');
if (isLoading) return <Spinner />;
return (
<div>
{isEnabled && <NewFeature />}
<Button color={value}>Click me</Button>
</div>
);
}
测试
内存中提供方
import { OpenFeature } from '@openfeature/server-sdk';
import { InMemoryProvider } from '@openfeature/in-memory-provider';
// Configure test flags
const testProvider = new InMemoryProvider({
'new-feature': {
variants: {
on: true,
off: false,
},
defaultVariant: 'off',
disabled: false,
},
'button-color': {
variants: {
blue: '#0066CC',
green: '#00CC66',
},
defaultVariant: 'blue',
disabled: false,
},
});
// Use in tests
beforeAll(async () => {
await OpenFeature.setProviderAndWait(testProvider);
});
afterAll(async () => {
await OpenFeature.close();
});
单元测试中的模拟
import { vi } from 'vitest';
import { OpenFeature } from '@openfeature/server-sdk';
// Mock the entire SDK
vi.mock('@openfeature/server-sdk', () => ({
OpenFeature: {
getClient: vi.fn().mockReturnValue({
getBooleanValue: vi.fn().mockResolvedValue(true),
getStringValue: vi.fn().mockResolvedValue('test-value'),
}),
},
}));
最佳实践
1. 尽早初始化
// Initialize before app starts handling requests
async function bootstrap() {
await initializeFeatureFlags(); // First
await initializeDatabase();
await startServer();
}
2. 使用有意义的标志名称
// Good: descriptive, namespaced
'checkout.new-payment-flow'
'dashboard.beta-analytics'
'api.rate-limit-v2'
// Bad: vague, unclear
'feature1'
'test-flag'
'enabled'
3. 始终提供默认值
// Good: safe default that works if provider fails
const isEnabled = await client.getBooleanValue('risky-feature', false);
// Consider: what's the safe behavior if flags fail?
const maxItems = await client.getNumberValue('max-items', 100); // Safe limit
4. 处理提供方错误
try {
const value = await client.getBooleanValue('feature', false);
} catch (error) {
// Log but don't crash - use default
logger.error('Feature flag evaluation failed', { error });
return defaultBehavior();
}
5. 清理旧标志
// Track flag usage with hooks
const flagUsageHook: Hook = {
after: (context, details) => {
metrics.increment(`feature_flag.${context.flagKey}.evaluations`);
},
};
// Regularly review and remove flags with 100% rollout
// or flags that haven't been evaluated in months
文档
- OpenFeature 规范:https://openfeature.dev/specification
- SDK 参考:https://openfeature.dev/docs/reference/concepts/evaluation-api
- 提供方列表:https://openfeature.dev/ecosystem
- 钩子指南:https://openfeature.dev/docs/reference/concepts/hooks
相关命令
/configure:feature-flags- 设置功能标志基础设施/configure:sentry- 错误跟踪(用于功能标志回滚监控)
评论
支持 Markdown