From 03e8d30f3421f48a5d320bed922b0a589c58aa59 Mon Sep 17 00:00:00 2001 From: Yoofi Quansah Date: Wed, 10 Jan 2024 22:41:16 -0600 Subject: [PATCH] feat(rust/java/node/python): Use enums for types with limited values for better type inference on caller side (#33) --- .../models/BooleanEvaluationResponse.java | 6 +-- .../models/ErrorEvaluationReason.java | 21 ++++++++++ .../models/ErrorEvaluationResponse.java | 6 +-- .../evaluation/models/EvaluationReason.java | 25 ++++++++++++ .../evaluation/models/EvaluationResponse.java | 6 +-- .../models/EvaluationResponseType.java | 23 +++++++++++ .../models/VariantEvaluationResponse.java | 6 +-- flipt-java/src/test/java/TestFliptClient.java | 17 +++++---- flipt-node/src/evaluation/models.ts | 23 +++++++++-- flipt-python/flipt/evaluation/models.py | 27 +++++++++++-- flipt-rust/src/evaluation/models.rs | 38 +++++++++++++++++-- flipt-rust/tests/integration.rs | 21 +++++----- 12 files changed, 178 insertions(+), 41 deletions(-) create mode 100644 flipt-java/src/main/java/io/flipt/api/evaluation/models/ErrorEvaluationReason.java create mode 100644 flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationReason.java create mode 100644 flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationResponseType.java diff --git a/flipt-java/src/main/java/io/flipt/api/evaluation/models/BooleanEvaluationResponse.java b/flipt-java/src/main/java/io/flipt/api/evaluation/models/BooleanEvaluationResponse.java index 4f68d15..b15951a 100644 --- a/flipt-java/src/main/java/io/flipt/api/evaluation/models/BooleanEvaluationResponse.java +++ b/flipt-java/src/main/java/io/flipt/api/evaluation/models/BooleanEvaluationResponse.java @@ -8,7 +8,7 @@ public class BooleanEvaluationResponse { private final String flagKey; - private final String reason; + private final EvaluationReason reason; private final float requestDurationMillis; @@ -18,7 +18,7 @@ public class BooleanEvaluationResponse { public BooleanEvaluationResponse( @JsonProperty("enabled") boolean enabled, @JsonProperty("flagKey") String flagKey, - @JsonProperty("reason") String reason, + @JsonProperty("reason") EvaluationReason reason, @JsonProperty("requestDurationMillis") float requestDurationMillis, @JsonProperty("timesteamp") String timestamp) { this.enabled = enabled; @@ -39,7 +39,7 @@ public String getFlagKey() { } @JsonProperty("reason") - public String getReason() { + public EvaluationReason getReason() { return reason; } diff --git a/flipt-java/src/main/java/io/flipt/api/evaluation/models/ErrorEvaluationReason.java b/flipt-java/src/main/java/io/flipt/api/evaluation/models/ErrorEvaluationReason.java new file mode 100644 index 0000000..3e447e8 --- /dev/null +++ b/flipt-java/src/main/java/io/flipt/api/evaluation/models/ErrorEvaluationReason.java @@ -0,0 +1,21 @@ +package io.flipt.api.evaluation.models; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum ErrorEvaluationReason { + UNKNOWN_ERROR_EVALUATION_REASON("UNKNOWN_ERROR_EVALUATION_REASON"), + + NOT_FOUND_ERROR_EVALUATION_REASON("NOT_FOUND_ERROR_EVALUATION_REASON"); + + private final String value; + + ErrorEvaluationReason(String value) { + this.value = value; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/flipt-java/src/main/java/io/flipt/api/evaluation/models/ErrorEvaluationResponse.java b/flipt-java/src/main/java/io/flipt/api/evaluation/models/ErrorEvaluationResponse.java index b10e691..40ccb2a 100644 --- a/flipt-java/src/main/java/io/flipt/api/evaluation/models/ErrorEvaluationResponse.java +++ b/flipt-java/src/main/java/io/flipt/api/evaluation/models/ErrorEvaluationResponse.java @@ -8,13 +8,13 @@ public class ErrorEvaluationResponse { private final String namespaceKey; - private final String reason; + private final ErrorEvaluationReason reason; @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) public ErrorEvaluationResponse( @JsonProperty("flagKey") String flagKey, @JsonProperty("namespaceKey") String namespaceKey, - @JsonProperty("reason") String reason) { + @JsonProperty("reason") ErrorEvaluationReason reason) { this.flagKey = flagKey; this.namespaceKey = namespaceKey; this.reason = reason; @@ -31,7 +31,7 @@ public String getNamespaceKey() { } @JsonProperty("reason") - public String getReason() { + public ErrorEvaluationReason getReason() { return reason; } } diff --git a/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationReason.java b/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationReason.java new file mode 100644 index 0000000..4d430e9 --- /dev/null +++ b/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationReason.java @@ -0,0 +1,25 @@ +package io.flipt.api.evaluation.models; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum EvaluationReason { + UNKNOWN_EVALUATION_REASON("UNKNOWN_EVALUATION_REASON"), + + FLAG_DISABLED_EVALUATION_REASON("FLAG_DISABLED_EVALUATION_REASON"), + + MATCH_EVALUATION_REASON("MATCH_EVALUATION_REASON"), + + DEFAULT_EVALUATION_REASON("DEFAULT_EVALUATION_REASON"); + + private final String value; + + EvaluationReason(String value) { + this.value = value; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationResponse.java b/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationResponse.java index ec53410..d5219d0 100644 --- a/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationResponse.java +++ b/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationResponse.java @@ -5,7 +5,7 @@ import java.util.Optional; public class EvaluationResponse { - private final String type; + private final EvaluationResponseType type; private final Optional booleanResponse; @@ -15,7 +15,7 @@ public class EvaluationResponse { @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) public EvaluationResponse( - @JsonProperty("type") String type, + @JsonProperty("type") EvaluationResponseType type, @JsonProperty("booleanResponse") Optional booleanResponse, @JsonProperty("variantResponse") Optional variantResponse, @JsonProperty("errorResponse") Optional errorResponse) { @@ -26,7 +26,7 @@ public EvaluationResponse( } @JsonProperty("type") - public String getType() { + public EvaluationResponseType getType() { return type; } diff --git a/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationResponseType.java b/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationResponseType.java new file mode 100644 index 0000000..8123cdc --- /dev/null +++ b/flipt-java/src/main/java/io/flipt/api/evaluation/models/EvaluationResponseType.java @@ -0,0 +1,23 @@ +package io.flipt.api.evaluation.models; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum EvaluationResponseType { + VARIANT_EVALUATION_RESPONSE_TYPE("VARIANT_EVALUATION_RESPONSE_TYPE"), + + BOOLEAN_EVALUATION_RESPONSE_TYPE("BOOLEAN_EVALUATION_RESPONSE_TYPE"), + + ERROR_EVALUATION_RESPONSE_TYPE("ERROR_EVALUATION_RESPONSE_TYPE"); + + private final String value; + + EvaluationResponseType(String value) { + this.value = value; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/flipt-java/src/main/java/io/flipt/api/evaluation/models/VariantEvaluationResponse.java b/flipt-java/src/main/java/io/flipt/api/evaluation/models/VariantEvaluationResponse.java index 509b55d..af40d86 100644 --- a/flipt-java/src/main/java/io/flipt/api/evaluation/models/VariantEvaluationResponse.java +++ b/flipt-java/src/main/java/io/flipt/api/evaluation/models/VariantEvaluationResponse.java @@ -7,7 +7,7 @@ public class VariantEvaluationResponse { private final boolean match; private final List segmentKeys; - private final String reason; + private final EvaluationReason reason; private final String flagKey; private final String variantKey; private final String variantAttachment; @@ -18,7 +18,7 @@ public class VariantEvaluationResponse { public VariantEvaluationResponse( @JsonProperty("match") boolean match, @JsonProperty("segmentKeys") List segmentKeys, - @JsonProperty("reason") String reason, + @JsonProperty("reason") EvaluationReason reason, @JsonProperty("flagKey") String flagKey, @JsonProperty("variantKey") String variantKey, @JsonProperty("variantAttachment") String variantAttachment, @@ -65,7 +65,7 @@ public String getFlagKey() { } @JsonProperty("reason") - public String getReason() { + public EvaluationReason getReason() { return reason; } diff --git a/flipt-java/src/test/java/TestFliptClient.java b/flipt-java/src/test/java/TestFliptClient.java index 6866f1b..f7f0c3d 100644 --- a/flipt-java/src/test/java/TestFliptClient.java +++ b/flipt-java/src/test/java/TestFliptClient.java @@ -28,7 +28,7 @@ void testVariant() { Assertions.assertTrue(variant.isMatch()); Assertions.assertEquals("flag1", variant.getFlagKey()); - Assertions.assertEquals("MATCH_EVALUATION_REASON", variant.getReason()); + Assertions.assertEquals("MATCH_EVALUATION_REASON", variant.getReason().toString()); Assertions.assertEquals("variant1", variant.getVariantKey()); Assertions.assertEquals("segment1", variant.getSegmentKeys().get(0)); } @@ -56,7 +56,7 @@ void testBoolean() { Assertions.assertTrue(booleanEvaluation.isEnabled()); Assertions.assertEquals("flag_boolean", booleanEvaluation.getFlagKey()); - Assertions.assertEquals("MATCH_EVALUATION_REASON", booleanEvaluation.getReason()); + Assertions.assertEquals("MATCH_EVALUATION_REASON", booleanEvaluation.getReason().toString()); } @Test @@ -93,31 +93,32 @@ void testBatch() { // Variant EvaluationResponse first = batch.getResponses().get(0); - Assertions.assertEquals("VARIANT_EVALUATION_RESPONSE_TYPE", first.getType()); + Assertions.assertEquals("VARIANT_EVALUATION_RESPONSE_TYPE", first.getType().toString()); VariantEvaluationResponse variant = first.getVariantResponse().get(); Assertions.assertTrue(variant.isMatch()); Assertions.assertEquals("flag1", variant.getFlagKey()); - Assertions.assertEquals("MATCH_EVALUATION_REASON", variant.getReason()); + Assertions.assertEquals("MATCH_EVALUATION_REASON", variant.getReason().toString()); Assertions.assertEquals("variant1", variant.getVariantKey()); Assertions.assertEquals("segment1", variant.getSegmentKeys().get(0)); // Boolean EvaluationResponse second = batch.getResponses().get(1); - Assertions.assertEquals("BOOLEAN_EVALUATION_RESPONSE_TYPE", second.getType()); + Assertions.assertEquals("BOOLEAN_EVALUATION_RESPONSE_TYPE", second.getType().toString()); BooleanEvaluationResponse booleanEvaluation = second.getBooleanResponse().get(); Assertions.assertTrue(booleanEvaluation.isEnabled()); Assertions.assertEquals("flag_boolean", booleanEvaluation.getFlagKey()); - Assertions.assertEquals("MATCH_EVALUATION_REASON", booleanEvaluation.getReason()); + Assertions.assertEquals("MATCH_EVALUATION_REASON", booleanEvaluation.getReason().toString()); // Error EvaluationResponse third = batch.getResponses().get(2); - Assertions.assertEquals("ERROR_EVALUATION_RESPONSE_TYPE", third.getType()); + Assertions.assertEquals("ERROR_EVALUATION_RESPONSE_TYPE", third.getType().toString()); ErrorEvaluationResponse errorEvaluation = third.getErrorResponse().get(); Assertions.assertEquals("flag1234", errorEvaluation.getFlagKey()); Assertions.assertEquals("default", errorEvaluation.getNamespaceKey()); - Assertions.assertEquals("NOT_FOUND_ERROR_EVALUATION_REASON", errorEvaluation.getReason()); + Assertions.assertEquals( + "NOT_FOUND_ERROR_EVALUATION_REASON", errorEvaluation.getReason().toString()); } } diff --git a/flipt-node/src/evaluation/models.ts b/flipt-node/src/evaluation/models.ts index f1e47e4..849b274 100644 --- a/flipt-node/src/evaluation/models.ts +++ b/flipt-node/src/evaluation/models.ts @@ -8,7 +8,7 @@ export interface EvaluationRequest { export interface VariantEvaluationResponse { match: boolean; segmentKeys: string[]; - reason: string; + reason: EvaluationReason; flagKey: string; variantKey: string; variantAttachment: string; @@ -19,7 +19,7 @@ export interface VariantEvaluationResponse { export interface BooleanEvaluationResponse { enabled: boolean; flagKey: string; - reason: string; + reason: EvaluationReason; requestDurationMillis: number; timestamp: string; } @@ -32,11 +32,11 @@ export interface BatchEvaluationRequest { interface ErrorEvaluationResponse { flagKey: string; namespaceKey: string; - reason: string; + reason: ErrorEvaluationReason; } export interface EvaluationResponse { - type: string; + type: EvaluationResponseType; booleanResponse?: BooleanEvaluationResponse; variantResponse?: VariantEvaluationResponse; errorResponse?: ErrorEvaluationResponse; @@ -47,3 +47,18 @@ export interface BatchEvaluationResponse { responses: EvaluationResponse[]; requestDurationMillis: number; } + +export type EvaluationResponseType = + | "VARIANT_EVALUATION_RESPONSE_TYPE" + | "BOOLEAN_EVALUATION_RESPONSE_TYPE" + | "ERROR_EVALUATION_RESPONSE_TYPE"; + +export type EvaluationReason = + | "UNKNOWN_EVALUATION_REASON" + | "FLAG_DISABLED_EVALUATION_REASON" + | "MATCH_EVALUATION_REASON" + | "DEFAULT_EVALUATION_REASON"; + +export type ErrorEvaluationReason = + | "UNKNOWN_ERROR_EVALUATION_REASON" + | "NOT_FOUND_ERROR_EVALUATION_REASON"; diff --git a/flipt-python/flipt/evaluation/models.py b/flipt-python/flipt/evaluation/models.py index 9674ed9..e083fd7 100644 --- a/flipt-python/flipt/evaluation/models.py +++ b/flipt-python/flipt/evaluation/models.py @@ -1,7 +1,26 @@ +import enum from pydantic import BaseModel, Field from typing import List, Optional +class EvaluationResponseType(str, enum.Enum): + VARIANT_EVALUATION_RESPONSE_TYPE = "VARIANT_EVALUATION_RESPONSE_TYPE" + BOOLEAN_EVALUATION_RESPONSE_TYPE = "BOOLEAN_EVALUATION_RESPONSE_TYPE" + ERROR_EVALUATION_RESPONSE_TYPE = "ERROR_EVALUATION_RESPONSE_TYPE" + + +class EvaluationReason(str, enum.Enum): + UNKNOWN_EVALUATION_REASON = "UNKNOWN_EVALUATION_REASON" + FLAG_DISABLED_EVALUATION_REASON = "FLAG_DISABLED_EVALUATION_REASON" + MATCH_EVALUATION_REASON = "MATCH_EVALUATION_REASON" + DEFAULT_EVALUATION_REASON = "DEFAULT_EVALUATION_REASON" + + +class ErrorEvaluationReason(str, enum.Enum): + UNKNOWN_ERROR_EVALUATION_REASON = "UNKNOWN_ERROR_EVALUATION_REASON" + NOT_FOUND_ERROR_EVALUATION_REASON = "NOT_FOUND_ERROR_EVALUATION_REASON" + + class EvaluationRequest(BaseModel): namespace_key: str = Field(default="default") flag_key: str @@ -17,7 +36,7 @@ class BatchEvaluationRequest(BaseModel): class VariantEvaluationResponse(BaseModel): match: bool segment_keys: List[str] = Field(..., alias="segmentKeys") - reason: str + reason: EvaluationReason flag_key: str = Field(..., alias="flagKey") variant_key: str = Field(..., alias="variantKey") variant_attachment: str = Field(..., alias="variantAttachment") @@ -28,7 +47,7 @@ class VariantEvaluationResponse(BaseModel): class BooleanEvaluationResponse(BaseModel): enabled: bool flag_key: str = Field(..., alias="flagKey") - reason: str + reason: EvaluationReason request_duration_millis: float = Field(..., alias="requestDurationMillis") timestamp: str @@ -36,11 +55,11 @@ class BooleanEvaluationResponse(BaseModel): class ErrorEvaluationReponse(BaseModel): flag_key: str = Field(..., alias="flagKey") namespace_key: str = Field(..., alias="namespaceKey") - reason: str + reason: ErrorEvaluationReason class EvaluationResponse(BaseModel): - type: str + type: EvaluationResponseType boolean_response: Optional[BooleanEvaluationResponse] = Field( default=None, alias="booleanResponse" ) diff --git a/flipt-rust/src/evaluation/models.rs b/flipt-rust/src/evaluation/models.rs index a9caa94..cd82c7f 100644 --- a/flipt-rust/src/evaluation/models.rs +++ b/flipt-rust/src/evaluation/models.rs @@ -20,7 +20,7 @@ pub struct EvaluationRequest { #[serde(rename_all = "camelCase")] pub struct BooleanEvaluationResponse { pub enabled: bool, - pub reason: String, + pub reason: EvaluationReason, pub request_id: String, pub request_duration_millis: f64, pub timestamp: DateTime, @@ -33,7 +33,7 @@ pub struct VariantEvaluationResponse { #[serde(rename = "match")] pub r#match: bool, pub segment_keys: Vec, - pub reason: String, + pub reason: EvaluationReason, pub variant_key: String, pub variant_attachment: String, pub request_id: String, @@ -47,7 +47,7 @@ pub struct VariantEvaluationResponse { pub struct ErrorEvaluationResponse { pub flag_key: String, pub namespace_key: String, - pub reason: String, + pub reason: ErrorEvaluationReason, } #[derive(Debug, Clone, Deserialize)] @@ -61,8 +61,38 @@ pub struct BatchEvaluationResponse { #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Response { - pub r#type: String, + pub r#type: EvaluationResponseType, pub boolean_response: Option, pub variant_response: Option, pub error_response: Option, } + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub enum EvaluationReason { + #[serde(rename = "UNKNOWN_EVALUATION_REASON")] + Unknown, + #[serde(rename = "FLAG_DISABLED_EVALUATION_REASON")] + FlagDisabled, + #[serde(rename = "MATCH_EVALUATION_REASON")] + Match, + #[serde(rename = "DEFAULT_EVALUATION_REASON")] + Default, +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub enum ErrorEvaluationReason { + #[serde(rename = "UNKNOWN_ERROR_EVALUATION_REASON")] + Unknown, + #[serde(rename = "NOT_FOUND_ERROR_EVALUATION_REASON")] + NotFound, +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub enum EvaluationResponseType { + #[serde(rename = "VARIANT_EVALUATION_RESPONSE_TYPE")] + Variant, + #[serde(rename = "BOOLEAN_EVALUATION_RESPONSE_TYPE")] + Boolean, + #[serde(rename = "ERROR_EVALUATION_RESPONSE_TYPE")] + Error, +} diff --git a/flipt-rust/tests/integration.rs b/flipt-rust/tests/integration.rs index 29ae1ee..f279d90 100644 --- a/flipt-rust/tests/integration.rs +++ b/flipt-rust/tests/integration.rs @@ -1,5 +1,8 @@ use flipt::api::FliptClient; -use flipt::evaluation::models::{BatchEvaluationRequest, EvaluationRequest}; +use flipt::evaluation::models::{ + BatchEvaluationRequest, ErrorEvaluationReason, EvaluationReason, EvaluationRequest, + EvaluationResponseType, +}; use flipt::{AuthScheme, Config}; use std::{collections::HashMap, env}; use url::Url; @@ -40,7 +43,7 @@ async fn tests() { assert!(variant.r#match); assert_eq!(variant.variant_key, "variant1"); - assert_eq!(variant.reason, "MATCH_EVALUATION_REASON"); + assert_eq!(variant.reason, EvaluationReason::Match); assert_eq!(variant.segment_keys.get(0).unwrap(), "segment1"); let boolean = flipt_client @@ -50,7 +53,7 @@ async fn tests() { .unwrap(); assert!(boolean.enabled); assert_eq!(boolean.flag_key, "flag_boolean"); - assert_eq!(boolean.reason, "MATCH_EVALUATION_REASON"); + assert_eq!(boolean.reason, EvaluationReason::Match); let mut requests: Vec = Vec::new(); requests.push(variant_request); @@ -67,29 +70,29 @@ async fn tests() { // Variant let first_response = batch.responses.get(0).unwrap(); - assert_eq!(first_response.r#type, "VARIANT_EVALUATION_RESPONSE_TYPE"); + assert_eq!(first_response.r#type, EvaluationResponseType::Variant); let variant = first_response.variant_response.clone().unwrap(); assert!(variant.r#match); assert_eq!(variant.variant_key, "variant1"); - assert_eq!(variant.reason, "MATCH_EVALUATION_REASON"); + assert_eq!(variant.reason, EvaluationReason::Match); assert_eq!(variant.segment_keys.get(0).unwrap(), "segment1"); // Boolean let second_response = batch.responses.get(1).unwrap(); - assert_eq!(second_response.r#type, "BOOLEAN_EVALUATION_RESPONSE_TYPE"); + assert_eq!(second_response.r#type, EvaluationResponseType::Boolean); let boolean = second_response.boolean_response.clone().unwrap(); assert!(boolean.enabled); assert_eq!(boolean.flag_key, "flag_boolean"); - assert_eq!(boolean.reason, "MATCH_EVALUATION_REASON"); + assert_eq!(boolean.reason, EvaluationReason::Match); // Error let third_response = batch.responses.get(2).unwrap(); - assert_eq!(third_response.r#type, "ERROR_EVALUATION_RESPONSE_TYPE"); + assert_eq!(third_response.r#type, EvaluationResponseType::Error); let error = third_response.error_response.clone().unwrap(); assert_eq!(error.flag_key, "notfound"); assert_eq!(error.namespace_key, "default"); - assert_eq!(error.reason, "NOT_FOUND_ERROR_EVALUATION_REASON"); + assert_eq!(error.reason, ErrorEvaluationReason::NotFound); }