forked from flipt-io/flipt-server-sdks
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FLI-783 - C# Server Side SDK](flipt-io#86) - Add Authentication - Add Evaluation (Boolean, Variant, and Batch) Signed-off-by: vgwizardx <[email protected]>
- Loading branch information
VgwizardX
committed
Jun 20, 2024
1 parent
87e9488
commit 816bce5
Showing
30 changed files
with
961 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
[*.cs] | ||
|
||
# IDE0290: Use primary constructor | ||
dotnet_diagnostic.IDE0290.severity = none | ||
csharp_indent_labels = one_less_than_current | ||
csharp_using_directive_placement = outside_namespace:silent | ||
csharp_prefer_simple_using_statement = true:suggestion | ||
csharp_prefer_braces = true:silent | ||
csharp_style_namespace_declarations = block_scoped:silent | ||
csharp_style_prefer_method_group_conversion = true:silent | ||
csharp_style_prefer_top_level_statements = true:silent | ||
csharp_style_prefer_primary_constructors = false:suggestion | ||
csharp_style_expression_bodied_methods = false:silent | ||
csharp_style_expression_bodied_constructors = false:silent | ||
csharp_style_expression_bodied_operators = false:silent | ||
csharp_style_expression_bodied_properties = true:silent | ||
csharp_style_expression_bodied_indexers = true:silent | ||
csharp_style_expression_bodied_accessors = true:silent | ||
csharp_style_expression_bodied_lambdas = true:silent | ||
csharp_style_expression_bodied_local_functions = false:silent | ||
csharp_space_around_binary_operators = before_and_after | ||
csharp_style_deconstructed_variable_declaration = true:suggestion | ||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent | ||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent | ||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent | ||
csharp_style_conditional_delegate_call = true:suggestion | ||
|
||
[*.{cs,vb}] | ||
#### Naming styles #### | ||
|
||
# Naming rules | ||
|
||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion | ||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface | ||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i | ||
|
||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion | ||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types | ||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case | ||
|
||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion | ||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members | ||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case | ||
|
||
# Symbol specifications | ||
|
||
dotnet_naming_symbols.interface.applicable_kinds = interface | ||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected | ||
dotnet_naming_symbols.interface.required_modifiers = | ||
|
||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum | ||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected | ||
dotnet_naming_symbols.types.required_modifiers = | ||
|
||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method | ||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected | ||
dotnet_naming_symbols.non_field_members.required_modifiers = | ||
|
||
# Naming styles | ||
|
||
dotnet_naming_style.begins_with_i.required_prefix = I | ||
dotnet_naming_style.begins_with_i.required_suffix = | ||
dotnet_naming_style.begins_with_i.word_separator = | ||
dotnet_naming_style.begins_with_i.capitalization = pascal_case | ||
|
||
dotnet_naming_style.pascal_case.required_prefix = | ||
dotnet_naming_style.pascal_case.required_suffix = | ||
dotnet_naming_style.pascal_case.word_separator = | ||
dotnet_naming_style.pascal_case.capitalization = pascal_case | ||
|
||
dotnet_naming_style.pascal_case.required_prefix = | ||
dotnet_naming_style.pascal_case.required_suffix = | ||
dotnet_naming_style.pascal_case.word_separator = | ||
dotnet_naming_style.pascal_case.capitalization = pascal_case | ||
dotnet_style_operator_placement_when_wrapping = beginning_of_line | ||
tab_width = 4 | ||
indent_size = 4 | ||
end_of_line = crlf | ||
dotnet_style_coalesce_expression = true:suggestion | ||
dotnet_style_prefer_collection_expression = true:suggestion | ||
dotnet_style_collection_initializer = true:suggestion | ||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent | ||
dotnet_style_prefer_conditional_expression_over_return = true:silent | ||
dotnet_style_prefer_compound_assignment = true:suggestion |
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,27 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.8.34316.72 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FliptCSharp", "src\FliptCSharp.csproj", "{5BAA5E95-A58B-4346-9C78-8076C81ED2D2}" | ||
EndProject | ||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{13F95778-A052-43D1-88B2-4AF06F7E1AC2}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{5BAA5E95-A58B-4346-9C78-8076C81ED2D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{5BAA5E95-A58B-4346-9C78-8076C81ED2D2}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{5BAA5E95-A58B-4346-9C78-8076C81ED2D2}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{5BAA5E95-A58B-4346-9C78-8076C81ED2D2}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {35FFF068-2AD7-470B-88B0-A8254F952CD7} | ||
EndGlobalSection | ||
EndGlobal |
18 changes: 18 additions & 0 deletions
18
flipt-csharp/src/Authentication/ClientTokenAuthenticationStrategy.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,18 @@ | ||
namespace FliptCSharp.Authentication; | ||
|
||
/// <summary> | ||
/// This class is responsible for providing the client token authentication strategy. | ||
/// </summary> | ||
public class ClientTokenAuthenticationStrategy : IAuthenticationStrategy | ||
{ | ||
private readonly string _clientToken; | ||
|
||
public ClientTokenAuthenticationStrategy(string clientToken) | ||
{ | ||
_clientToken = clientToken; | ||
} | ||
public string GetAuthorizationHeader() | ||
{ | ||
return $"Bearer {_clientToken}"; | ||
} | ||
} |
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 FliptCSharp.Authentication; | ||
|
||
/// <summary> | ||
/// This interface is responsible for providing the authentication strategy. | ||
/// </summary> | ||
public interface IAuthenticationStrategy | ||
{ | ||
string GetAuthorizationHeader(); | ||
} |
19 changes: 19 additions & 0 deletions
19
flipt-csharp/src/Authentication/JWTAuthenticationStrategy.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 FliptCSharp.Authentication; | ||
|
||
/// <summary> | ||
/// This class is responsible for providing the JWT authentication strategy. | ||
/// </summary> | ||
public class JWTAuthenticationStrategy : IAuthenticationStrategy | ||
{ | ||
private readonly string _jwtToken; | ||
|
||
public JWTAuthenticationStrategy(string jwtToken) | ||
{ | ||
_jwtToken = jwtToken; | ||
} | ||
|
||
public string GetAuthorizationHeader() | ||
{ | ||
return $"JWT {_jwtToken}"; | ||
} | ||
} |
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,155 @@ | ||
using System.Net.Http.Headers; | ||
using System.Text; | ||
using System.Text.Json; | ||
using FliptCSharp.Authentication; | ||
using FliptCSharp.DTOs; | ||
|
||
namespace FliptCSharp.Clients; | ||
/// <summary> | ||
/// This class is responsible for making requests to the Flipt server to evaluate flags. | ||
/// </summary> | ||
public class Evaluation | ||
{ | ||
private readonly HttpClient _httpClient; | ||
private readonly string _baseUrl; | ||
private readonly IAuthenticationStrategy? _authenticationStrategy; | ||
private readonly IDictionary<string, string>? _headers; | ||
|
||
/// <summary> | ||
/// This method creates a new instance of the Evaluation class. | ||
/// </summary> | ||
/// <param name="builder"></param> | ||
private Evaluation(EvaluationBuilder builder) | ||
{ | ||
_httpClient = builder.HttpClient; | ||
_baseUrl = builder.BaseUrl; | ||
_authenticationStrategy = builder.AuthenticationStrategy; | ||
_headers = builder.Headers; | ||
} | ||
|
||
/// <summary> | ||
/// This method returns a new instance of the EvaluationBuilder class. | ||
/// </summary> | ||
/// <returns></returns> | ||
public static EvaluationBuilder Builder() | ||
{ | ||
return new EvaluationBuilder(); | ||
} | ||
|
||
/// <summary> | ||
/// This class is a builder for the Evaluation class. | ||
/// </summary> | ||
public class EvaluationBuilder | ||
{ | ||
public HttpClient HttpClient { get; private set; } = null!; | ||
public string BaseUrl { get; private set; } = null!; | ||
public IAuthenticationStrategy? AuthenticationStrategy { get; private set; } | ||
public IDictionary<string, string>? Headers { get; private set; } | ||
|
||
public EvaluationBuilder WithHttpClient(HttpClient httpClient) | ||
{ | ||
HttpClient = httpClient; | ||
return this; | ||
} | ||
|
||
public EvaluationBuilder WithBaseUrl(string baseUrl) | ||
{ | ||
BaseUrl = baseUrl; | ||
return this; | ||
} | ||
|
||
public EvaluationBuilder WithAuthenticationStrategy(IAuthenticationStrategy? authenticationStrategy) | ||
{ | ||
AuthenticationStrategy = authenticationStrategy; | ||
return this; | ||
} | ||
|
||
public EvaluationBuilder WithHeaders(IDictionary<string, string>? headers) | ||
{ | ||
Headers = headers; | ||
return this; | ||
} | ||
|
||
public Evaluation Build() | ||
{ | ||
if (HttpClient == null) | ||
{ | ||
throw new InvalidOperationException("HttpClient must be provided."); | ||
} | ||
|
||
if (string.IsNullOrEmpty(BaseUrl)) | ||
{ | ||
throw new InvalidOperationException("BaseURL must be provided."); | ||
} | ||
|
||
return new Evaluation(this); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// This method evaluates a variant for a given flag key and entity id. | ||
/// </summary> | ||
/// <param name="request"></param> | ||
/// <returns></returns> | ||
public async Task<VariantEvaluationResponse?> EvaluateVariantAsync(EvaluationRequest request) | ||
{ | ||
return await EvaluateAsync<VariantEvaluationResponse>("/evaluate/v1/variant", request); | ||
} | ||
|
||
/// <summary> | ||
/// This method evaluates a boolean flag for a given flag key and entity id. | ||
/// </summary> | ||
/// <param name="request"></param> | ||
/// <returns></returns> | ||
public async Task<BooleanEvaluationResponse?> EvaluateBooleanAsync(EvaluationRequest request) | ||
{ | ||
return await EvaluateAsync<BooleanEvaluationResponse>("/evaluate/v1/boolean", request); | ||
} | ||
|
||
/// <summary> | ||
/// This method evaluates a batch of flags for a given flag key and entity id. | ||
/// </summary> | ||
/// <param name="request"></param> | ||
/// <returns></returns> | ||
public async Task<BatchEvaluationResponse?> EvaluateBatchAsync(BatchEvaluationRequest request) | ||
{ | ||
return await EvaluateAsync<BatchEvaluationResponse>("/evaluate/v1/batch", request); | ||
} | ||
|
||
/// <summary> | ||
/// This method evaluates a flag for a given flag key and entity id. | ||
/// </summary> | ||
/// <typeparam name="T"></typeparam> | ||
/// <param name="path"></param> | ||
/// <param name="request"></param> | ||
/// <returns></returns> | ||
private async Task<T?> EvaluateAsync<T>(string path, object request) | ||
{ | ||
var url = new Uri(new Uri(_baseUrl), path); | ||
|
||
var jsonContent = JsonSerializer.Serialize(request); | ||
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); | ||
|
||
var httpRequest = new HttpRequestMessage(HttpMethod.Post, url) | ||
{ | ||
Content = content | ||
}; | ||
|
||
if (_headers != null) | ||
foreach (var header in _headers) | ||
{ | ||
httpRequest.Headers.Add(header.Key, header.Value); | ||
} | ||
|
||
if (_authenticationStrategy != null) | ||
httpRequest.Headers.Authorization = | ||
new AuthenticationHeaderValue("Bearer", _authenticationStrategy.GetAuthorizationHeader()); | ||
|
||
var response = await _httpClient.SendAsync(httpRequest); | ||
response.EnsureSuccessStatusCode(); | ||
|
||
var responseContent = await response.Content.ReadAsStringAsync(); | ||
return string.IsNullOrEmpty(responseContent) ? default : JsonSerializer.Deserialize<T>(responseContent); | ||
} | ||
|
||
} |
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 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
namespace FliptCSharp.DTOs; | ||
|
||
/// <summary> | ||
/// Represents a batch evaluation request. | ||
/// </summary> | ||
public class BatchEvaluationRequest | ||
{ | ||
public BatchEvaluationRequest(List<EvaluationRequest> evaluationRequests) | ||
{ | ||
EvaluationRequests = evaluationRequests; | ||
} | ||
public string? RequestId { get; set; } | ||
|
||
[Required] | ||
public List<EvaluationRequest> EvaluationRequests { get; set; } | ||
public string? Reference { get; set; } | ||
} |
Oops, something went wrong.