@@ -41,7 +41,9 @@ Abstract
41
41
42
42
OpenFeature is an open standard and ecosystem for managing feature toggles across
43
43
various languages and frameworks. This offers a single, consistent format for managing
44
- the ubiquitous toggles in Open edX to improve their discoverability and maintenance.
44
+ the ubiquitous toggles in Open edX to improve their discoverability and maintenance. The
45
+ core problem that adoption of OpenFeature addresses is the need to synchronize different
46
+ toggle settings across the boundaries of repositories and processes.
45
47
46
48
Motivation
47
49
**********
@@ -78,6 +80,19 @@ the adoption of OpenFeature, the differently named toggles that share purpose ac
78
80
repositories will be aligned. This will enable operators to manage a single toggle
79
81
setting to enable the functionality across the full Open edX stack.
80
82
83
+ The adoption of OpenFeature will be through the use of their provided Python and
84
+ JavaScript SDKs. Those SDKs already encapsulate the interfaces mandated by the
85
+ specification, freeing the Open edX community from having to implement those
86
+ capabilities on their own. The adoption of those SDKs can happen within the existing
87
+ libraries used and maintained by the Open edX community, namely edx-toggles for IDAs and
88
+ frontend-platform for MFEs.
89
+
90
+ The current approach of annotating toggles with explicit metadata will be
91
+ maintained. The OpenFeature specification and client implementations do not provide any
92
+ method for annotating flags in the context of the source code. Providers are able to
93
+ populate metadata that is returned as part of the evaluation response, but this is not
94
+ versioned and maintained in the Open edX projects.
95
+
81
96
Rationale
82
97
*********
83
98
@@ -99,11 +114,88 @@ Waffle, but that will be created as part of the adoption process for this propos
99
114
Reference Implementation
100
115
************************
101
116
102
- The reference implementation must be completed before any OEP is given "Final"
103
- status, but it need not be completed before the OEP is "Accepted". While there is
104
- merit to the approach of reaching consensus on the specification and rationale
105
- before writing code, the principle of "rough consensus and running code" is
106
- still useful when it comes to resolving many discussions.
117
+ An example implementation of a Python provider that retrieves toggle values from Django settings could look like this:
118
+
119
+ .. code-block :: python
120
+
121
+ from typing import Any, Dict
122
+ from django.conf import settings
123
+ from openfeature.provider.provider import AbstractProvider
124
+ from openfeature.flag_evaluation import FlagResolutionDetails, EvaluationContext
125
+
126
+ class DjangoSettingsProvider (AbstractProvider ):
127
+ def __init__ (self ):
128
+ super ().__init__ ()
129
+ self .name = " Django Settings Provider"
130
+
131
+ def get_metadata (self ):
132
+ return {" name" : self .name}
133
+
134
+ def get_bool_value (
135
+ self ,
136
+ flag_key : str ,
137
+ default_value : bool ,
138
+ evaluation_context : EvaluationContext = None ,
139
+ ) -> FlagResolutionDetails[bool ]:
140
+ value = self ._get_flag_value(flag_key, default_value)
141
+ return FlagResolutionDetails(value = bool (value))
142
+
143
+ def get_string_value (
144
+ self ,
145
+ flag_key : str ,
146
+ default_value : str ,
147
+ evaluation_context : EvaluationContext = None ,
148
+ ) -> FlagResolutionDetails[str ]:
149
+ value = self ._get_flag_value(flag_key, default_value)
150
+ return FlagResolutionDetails(value = str (value))
151
+
152
+ def get_integer_value (
153
+ self ,
154
+ flag_key : str ,
155
+ default_value : int ,
156
+ evaluation_context : EvaluationContext = None ,
157
+ ) -> FlagResolutionDetails[int ]:
158
+ value = self ._get_flag_value(flag_key, default_value)
159
+ return FlagResolutionDetails(value = int (value))
160
+
161
+ def get_float_value (
162
+ self ,
163
+ flag_key : str ,
164
+ default_value : float ,
165
+ evaluation_context : EvaluationContext = None ,
166
+ ) -> FlagResolutionDetails[float ]:
167
+ value = self ._get_flag_value(flag_key, default_value)
168
+ return FlagResolutionDetails(value = float (value))
169
+
170
+ def get_object_value (
171
+ self ,
172
+ flag_key : str ,
173
+ default_value : Dict,
174
+ evaluation_context : EvaluationContext = None ,
175
+ ) -> FlagResolutionDetails[Dict]:
176
+ value = self ._get_flag_value(flag_key, default_value)
177
+ return FlagResolutionDetails(value = dict (value))
178
+
179
+ def _get_flag_value (self , flag_key : str , default_value : Any) -> Any:
180
+ return getattr (settings, flag_key, default_value)
181
+
182
+
183
+ Usage of the above provider could look like:
184
+
185
+ .. code-block :: python
186
+
187
+ import openfeature.api
188
+ from django.conf import settings
189
+
190
+ # In your Django settings.py
191
+ FEATURE_FLAG_EXAMPLE = True
192
+
193
+ # In your application code
194
+ client = openfeature.api.get_client(" edx" )
195
+ openfeature.api.set_provider(DjangoSettingsProvider())
196
+
197
+ # Evaluate a flag
198
+ is_enabled = client.get_boolean_value(" FEATURE_FLAG_EXAMPLE" , False )
107
199
108
200
Rejected Alternatives
109
201
*********************
0 commit comments