Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ResolveAll endpoint for bulk evaluation #118

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions providers/Flagd/src/FlagdProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,9 @@ public function resolveObjectValue(string $flagKey, mixed $defaultValue, ?Evalua
{
return $this->service->resolveValue($flagKey, FlagValueType::OBJECT, $defaultValue, $context);
}

public function resolveAllValues(?EvaluationContext $context = null): array
{
return $this->service->resolveValues($context);
}
}
22 changes: 22 additions & 0 deletions providers/Flagd/src/http/FlagdResponseResolutionAllAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types = 1);

namespace OpenFeature\Providers\Flagd\http;

use DateTime;
use OpenFeature\interfaces\provider\ResolutionDetails;

class FlagdResponseResolutionAllAdapter
{
/**
* @param array{flags: array{array{value: mixed[]|bool|DateTime|float|int|string|null, variant: ?string, reason: ?string}}} $response
* @return ResolutionDetails[]
*/
public static function forSuccess(array $response): array
{
return array_map(
fn($flagDetails) => FlagdResponseResolutionDetailsAdapter::forSuccess($flagDetails), $response['flags']
);
}
}
1 change: 1 addition & 0 deletions providers/Flagd/src/http/GrpcWebEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ class GrpcWebEndpoint
public const FLOAT = 'schema.v1.Service/ResolveFloat';
public const INTEGER = 'schema.v1.Service/ResolveInt';
public const OBJECT = 'schema.v1.Service/ResolveObject';
public const ALL = 'schema.v1.Service/ResolveAll';
}
14 changes: 13 additions & 1 deletion providers/Flagd/src/http/HttpService.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,24 @@ public function resolveValue(string $flagKey, string $flagType, $defaultValue, ?
return FlagdResponseResolutionDetailsAdapter::forSuccess($validDetails);
}

public function resolveValues(?EvaluationContext $context): array
{
$response = $this->sendRequest(GrpcWebEndpoint::ALL, null, $context);
/** @var string[] $details */
$details = json_decode((string) $response->getBody(), true);

/** @var array{flags: array{array{value: mixed[]|bool|DateTime|float|int|string|null, variant: ?string, reason: ?string}}} $validDetails */
$validDetails = $details;

return FlagdResponseResolutionAllAdapter::forSuccess($validDetails);
}

private function buildRoute(string $path): string
{
return $this->target . '/' . $path;
}

private function sendRequest(string $path, string $flagKey, ?EvaluationContext $context): ResponseInterface
private function sendRequest(string $path, ?string $flagKey, ?EvaluationContext $context): ResponseInterface
{
/**
* This method is equivalent to:
Expand Down
5 changes: 5 additions & 0 deletions providers/Flagd/src/service/ServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ interface ServiceInterface
* @param mixed[]|bool|DateTime|float|int|string|null $defaultValue
*/
public function resolveValue(string $flagKey, string $flagType, mixed $defaultValue, ?EvaluationContext $context): ResolutionDetails;

/**
* @return ResolutionDetails[]
*/
public function resolveValues(?EvaluationContext $context): array;
}
58 changes: 47 additions & 11 deletions providers/Flagd/tests/unit/FlagdProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,22 @@ public function testCanInstantiateHttpWithConfigObject(): void
$mockStreamFactory->shouldReceive('createStream')->andReturn($mockStream);

$mockResponse = $this->mockery(ResponseInterface::class);
$mockResponse->shouldReceive('getBody->__toString')->andReturn("{
\"value\":\"{$expectedValue}\",
\"variant\":\"{$expectedVariant}\",
\"reason\":\"{$expectedReason}\"
}");
$mockResponse->shouldReceive('getBody->__toString')->andReturn(
"{
\"value\":\"{$expectedValue}\",
\"variant\":\"{$expectedVariant}\",
\"reason\":\"{$expectedReason}\"
}",
"{
\"flags\":{
\"any-key\":
{\"reason\":\"{$expectedReason}\",
\"variant\":\"{$expectedVariant}\",
\"doubleValue\":\"{$expectedValue}\"
}
}
}"
);

$mockClient = $this->mockery(ClientInterface::class);
$mockClient->shouldReceive('sendRequest')->with($mockRequest)->andReturn($mockResponse);
Expand Down Expand Up @@ -90,6 +101,13 @@ public function testCanInstantiateHttpWithConfigObject(): void
$this->assertEquals($expectedValue, $actualDetails->getValue());
$this->assertEquals($expectedVariant, $actualDetails->getVariant());
$this->assertEquals($expectedReason, $actualDetails->getReason());

$actualFlagsDetails = $provider->resolveAllValues(null);

// Then
$this->assertEquals($expectedValue, $actualFlagsDetails['any-key']->getValue());
$this->assertEquals($expectedVariant, $actualFlagsDetails['any-key']->getVariant());
$this->assertEquals($expectedReason, $actualFlagsDetails['any-key']->getReason());
}

public function testCanInstantiateHttpWithConfigArray(): void
Expand All @@ -112,12 +130,23 @@ public function testCanInstantiateHttpWithConfigArray(): void
$mockStreamFactory->shouldReceive('createStream')->andReturn($mockStream);

$mockResponse = $this->mockery(ResponseInterface::class);
$mockResponse->shouldReceive('getBody->__toString')->andReturn("{
\"value\":\"{$expectedValue}\",
\"variant\":\"{$expectedVariant}\",
\"reason\":\"{$expectedReason}\"
}");

$mockResponse->shouldReceive('getBody->__toString')->andReturn(
"{
\"value\":\"{$expectedValue}\",
\"variant\":\"{$expectedVariant}\",
\"reason\":\"{$expectedReason}\"
}",
"{
\"flags\":{
\"any-key\":
{\"reason\":\"{$expectedReason}\",
\"variant\":\"{$expectedVariant}\",
\"doubleValue\":\"{$expectedValue}\"
}
}
}"
);

$mockClient = $this->mockery(ClientInterface::class);
$mockClient->shouldReceive('sendRequest')->with($mockRequest)->andReturn($mockResponse);

Expand Down Expand Up @@ -148,5 +177,12 @@ public function testCanInstantiateHttpWithConfigArray(): void
$this->assertEquals($expectedValue, $actualDetails->getValue());
$this->assertEquals($expectedVariant, $actualDetails->getVariant());
$this->assertEquals($expectedReason, $actualDetails->getReason());

$actualFlagsDetails = $provider->resolveAllValues(null);

// Then
$this->assertEquals($expectedValue, $actualFlagsDetails['any-key']->getValue());
$this->assertEquals($expectedVariant, $actualFlagsDetails['any-key']->getVariant());
$this->assertEquals($expectedReason, $actualFlagsDetails['any-key']->getReason());
}
}
Loading