-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: GO Feature Flag dotnet provider (#24)
GO Feature Flag dotnet provider Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
- Loading branch information
1 parent
831c10c
commit 964cf32
Showing
22 changed files
with
1,352 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
src/OpenFeature.Contrib.Providers.GOFeatureFlag/GOFeatureFlagRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
namespace OpenFeature.Contrib.Providers.GOFeatureFlag | ||
{ | ||
/// <summary> | ||
/// GOFeatureFlagRequest is the object formatting the request to the relay proxy. | ||
/// </summary> | ||
/// <typeparam name="T">Type of the default value.</typeparam> | ||
public class GOFeatureFlagRequest<T> | ||
{ | ||
/// <summary> | ||
/// GoFeatureFlagUser is the representation of the user. | ||
/// </summary> | ||
public GoFeatureFlagUser User { get; set; } | ||
|
||
/// <summary> | ||
/// default value if we have an error. | ||
/// </summary> | ||
public T DefaultValue { get; set; } | ||
} | ||
} |
326 changes: 326 additions & 0 deletions
326
src/OpenFeature.Contrib.Providers.GOFeatureFlag/GoFeatureFlagProvider.cs
Large diffs are not rendered by default.
Oops, something went wrong.
29 changes: 29 additions & 0 deletions
29
src/OpenFeature.Contrib.Providers.GOFeatureFlag/GoFeatureFlagProviderOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using System; | ||
using System.Net.Http; | ||
|
||
namespace OpenFeature.Contrib.Providers.GOFeatureFlag | ||
{ | ||
/// <Summary> | ||
/// GoFeatureFlagProviderOptions contains the options to initialise the provider. | ||
/// </Summary> | ||
public class GoFeatureFlagProviderOptions | ||
{ | ||
/// <Summary> | ||
/// (mandatory) endpoint contains the DNS of your GO Feature Flag relay proxy | ||
/// example: https://mydomain.com/gofeatureflagproxy/ | ||
/// </Summary> | ||
public string Endpoint { get; set; } | ||
|
||
/// <Summary> | ||
/// (optional) timeout we are waiting when calling the go-feature-flag relay proxy API. | ||
/// Default: 10000 ms | ||
/// </Summary> | ||
public TimeSpan Timeout { get; set; } = new TimeSpan(10000 * TimeSpan.TicksPerMillisecond); | ||
|
||
/// <Summary> | ||
/// (optional) If you want to provide your own HttpMessageHandler. | ||
/// Default: null | ||
/// </Summary> | ||
public HttpMessageHandler HttpMessageHandler { get; set; } | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
src/OpenFeature.Contrib.Providers.GOFeatureFlag/GoFeatureFlagResponse.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
namespace OpenFeature.Contrib.Providers.GOFeatureFlag | ||
{ | ||
/// <summary> | ||
/// GoFeatureFlagResponse is the response returned by the relay proxy. | ||
/// </summary> | ||
public class GoFeatureFlagResponse | ||
{ | ||
/// <summary> | ||
/// trackEvent is true when this call was tracked in GO Feature Flag. | ||
/// </summary> | ||
public bool trackEvents { get; set; } | ||
|
||
/// <summary> | ||
/// variationType contains the name of the variation used for this flag. | ||
/// </summary> | ||
public string variationType { get; set; } | ||
|
||
/// <summary> | ||
/// failed is true if GO Feature Flag had an issue. | ||
/// </summary> | ||
public bool failed { get; set; } | ||
|
||
/// <summary> | ||
/// version of the flag used (optional) | ||
/// </summary> | ||
public string version { get; set; } | ||
|
||
/// <summary> | ||
/// reason used to choose this variation. | ||
/// </summary> | ||
public string reason { get; set; } | ||
|
||
/// <summary> | ||
/// errorCode is empty if everything went ok. | ||
/// </summary> | ||
public string errorCode { get; set; } | ||
|
||
/// <summary> | ||
/// value contains the result of the flag. | ||
/// </summary> | ||
public object value { get; set; } | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
src/OpenFeature.Contrib.Providers.GOFeatureFlag/GoFeatureFlagUser.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using OpenFeature.Contrib.Providers.GOFeatureFlag.exception; | ||
using OpenFeature.Model; | ||
|
||
namespace OpenFeature.Contrib.Providers.GOFeatureFlag | ||
{ | ||
/// <summary> | ||
/// GOFeatureFlagUser is the representation of a User inside GO Feature Flag. | ||
/// </summary> | ||
public class GoFeatureFlagUser | ||
{ | ||
private const string AnonymousField = "anonymous"; | ||
private const string KeyField = "targetingKey"; | ||
private string Key { get; set; } | ||
private bool Anonymous { get; set; } | ||
private Dictionary<string, object> Custom { get; set; } | ||
|
||
/** | ||
* FromEvaluationContext convert the evaluation context into a GOFeatureFlagUser Object. | ||
*/ | ||
public static GoFeatureFlagUser FromEvaluationContext(EvaluationContext ctx) | ||
{ | ||
try | ||
{ | ||
if (ctx is null) | ||
throw new InvalidEvaluationContext("GO Feature Flag need an Evaluation context to work."); | ||
if (!ctx.GetValue(KeyField).IsString) | ||
throw new InvalidTargetingKey("targetingKey field MUST be a string."); | ||
} | ||
catch (KeyNotFoundException e) | ||
{ | ||
throw new InvalidTargetingKey("targetingKey field is mandatory.", e); | ||
} | ||
|
||
var anonymous = ctx.ContainsKey(AnonymousField) && ctx.GetValue(AnonymousField).IsBoolean | ||
? ctx.GetValue(AnonymousField).AsBoolean | ||
: false; | ||
|
||
var custom = ctx.AsDictionary().ToDictionary(x => x.Key, x => x.Value.AsObject); | ||
custom.Remove(AnonymousField); | ||
custom.Remove(KeyField); | ||
|
||
return new GoFeatureFlagUser | ||
{ | ||
Key = ctx.GetValue("targetingKey").AsString, | ||
Anonymous = anonymous.Value, | ||
Custom = custom | ||
}; | ||
} | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
...eature.Contrib.Providers.GOFeatureFlag/OpenFeature.Contrib.Providers.GOFeatureFlag.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<PackageId>OpenFeature.Contrib.GOFeatureFlag</PackageId> | ||
<VersionNumber>0.1.0</VersionNumber> <!--x-release-please-version --> | ||
<Version>$(VersionNumber)</Version> | ||
<AssemblyVersion>$(VersionNumber)</AssemblyVersion> | ||
<FileVersion>$(VersionNumber)</FileVersion> | ||
<Description>GO Feature Flag provider for .NET</Description> | ||
<PackageProjectUrl>https://gofeatureflag.org</PackageProjectUrl> | ||
<RepositoryUrl>https://github.com/open-feature/dotnet-sdk-contrib</RepositoryUrl> | ||
<Authors>Thomas Poignant</Authors> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="System.Text.Json" Version="7.0.0" /> | ||
</ItemGroup> | ||
|
||
<PropertyGroup> | ||
<LangVersion>8.0</LangVersion> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# GO Feature Flag .NET Provider | ||
|
||
GO Feature Flag provider allows you to connect to your GO Feature Flag instance. | ||
|
||
[GO Feature Flag](https://gofeatureflag.org) believes in simplicity and offers a simple and lightweight solution to use feature flags. | ||
Our focus is to avoid any complex infrastructure work to use GO Feature Flag. | ||
|
||
This is a complete feature flagging solution with the possibility to target only a group of users, use any types of flags, store your configuration in various location and advanced rollout functionality. You can also collect usage data of your flags and be notified of configuration changes. | ||
|
||
# .Net SDK usage | ||
|
||
## Install dependencies | ||
|
||
The first things we will do is install the **Open Feature SDK** and the **GO Feature Flag provider**. | ||
|
||
### .NET Cli | ||
```shell | ||
dotnet add package OpenFeature.Contrib.Providers.GOFeatureFlag | ||
``` | ||
### Package Manager | ||
|
||
```shell | ||
NuGet\Install-Package OpenFeature.Contrib.Providers.GOFeatureFlag | ||
``` | ||
### Package Reference | ||
|
||
```xml | ||
<PackageReference Include="OpenFeature.Contrib.Providers.GOFeatureFlag" /> | ||
``` | ||
### Packet cli | ||
|
||
```shell | ||
paket add OpenFeature.Contrib.Providers.GOFeatureFlag | ||
``` | ||
|
||
### Cake | ||
|
||
```shell | ||
// Install OpenFeature.Contrib.Providers.GOFeatureFlag as a Cake Addin | ||
#addin nuget:?package=OpenFeature.Contrib.Providers.GOFeatureFlag | ||
|
||
// Install OpenFeature.Contrib.Providers.GOFeatureFlag as a Cake Tool | ||
#tool nuget:?package=OpenFeature.Contrib.Providers.GOFeatureFlag | ||
``` | ||
|
||
## Initialize your Open Feature client | ||
|
||
To evaluate the flags you need to have an Open Feature configured in you app. | ||
This code block shows you how you can create a client that you can use in your application. | ||
|
||
```csharp | ||
using OpenFeature; | ||
using OpenFeature.Contrib.Providers.GOFeatureFlag; | ||
|
||
// ... | ||
var goFeatureFlagProvider = new GoFeatureFlagProvider(new GoFeatureFlagProviderOptions | ||
{ | ||
Endpoint = "http://localhost:1031/", | ||
Timeout = new TimeSpan(1000 * TimeSpan.TicksPerMillisecond) | ||
}); | ||
Api.Instance.SetProvider(goFeatureFlagProvider); | ||
var client = Api.Instance.GetClient("my-app"); | ||
``` | ||
|
||
## Evaluate your flag | ||
|
||
This code block explain how you can create an `EvaluationContext` and use it to evaluate your flag. | ||
|
||
|
||
> In this example we are evaluating a `boolean` flag, but other types are available. | ||
> | ||
> **Refer to the [Open Feature documentation](https://docs.openfeature.dev/docs/reference/concepts/evaluation-api#basic-evaluation) to know more about it.** | ||
```csharp | ||
// Context of your flag evaluation. | ||
// With GO Feature Flag you MUST have a targetingKey that is a unique identifier of the user. | ||
var userContext = EvaluationContext.Builder() | ||
.Set("targetingKey", "1d1b9238-2591-4a47-94cf-d2bc080892f1") // user unique identifier (mandatory) | ||
.Set("firstname", "john") | ||
.Set("lastname", "doe") | ||
.Set("email", "john.doe@gofeatureflag.org") | ||
.Set("admin", true) // this field is used in the targeting rule of the flag "flag-only-for-admin" | ||
.Set("anonymous", false) | ||
.Build(); | ||
|
||
var adminFlag = await client.GetBooleanValue("flag-only-for-admin", false, userContext); | ||
if (adminFlag) { | ||
// flag "flag-only-for-admin" is true for the user | ||
} else { | ||
// flag "flag-only-for-admin" is false for the user | ||
} | ||
``` |
9 changes: 9 additions & 0 deletions
9
src/OpenFeature.Contrib.Providers.GOFeatureFlag/exception/FlagDisabled.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace OpenFeature.Contrib.Providers.GOFeatureFlag.exception | ||
{ | ||
/// <summary> | ||
/// Exception thrown when a flag is disabled | ||
/// </summary> | ||
public class FlagDisabled : GoFeatureFlagException | ||
{ | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/OpenFeature.Contrib.Providers.GOFeatureFlag/exception/FlagNotFoundError.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System; | ||
using OpenFeature.Constant; | ||
using OpenFeature.Error; | ||
|
||
namespace OpenFeature.Contrib.Providers.GOFeatureFlag.exception | ||
{ | ||
/// <summary> | ||
/// Exception thrown when the flag is not found by GO Feature Flag relay proxy. | ||
/// </summary> | ||
public class FlagNotFoundError : FeatureProviderException | ||
{ | ||
/// <summary> | ||
/// Constructor of the exception | ||
/// </summary> | ||
/// <param name="message">Message to display</param> | ||
/// <param name="innerException">Original exception</param> | ||
public FlagNotFoundError(string message, Exception innerException = null) : base(ErrorType.FlagNotFound, | ||
message, innerException) | ||
{ | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/OpenFeature.Contrib.Providers.GOFeatureFlag/exception/GeneralError.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System; | ||
using OpenFeature.Constant; | ||
using OpenFeature.Error; | ||
|
||
namespace OpenFeature.Contrib.Providers.GOFeatureFlag.exception | ||
{ | ||
/// <summary> | ||
/// Exception throw when we don't have a specific case. | ||
/// </summary> | ||
public class GeneralError : FeatureProviderException | ||
{ | ||
/// <summary> | ||
/// Constructor of the exception | ||
/// </summary> | ||
/// <param name="message">Message to display</param> | ||
/// <param name="innerException">Original exception</param> | ||
public GeneralError(string message, Exception innerException = null) : base(ErrorType.General, message, | ||
innerException) | ||
{ | ||
} | ||
} | ||
} |
Oops, something went wrong.