Unleash / unleash-client-rust

Unleash client SDK for Rust language projects
Apache License 2.0
23 stars 17 forks source link

Implement Global Segments #44

Open sighphyre opened 2 years ago

sighphyre commented 2 years ago

Is there an existing issue for this?

Describe the new feature

Just a feature that needs to be implemented - Global Segments. Unleash v4.13 supports enhanced responses for global segments, it would be great if this SDK can make use of this.

Background

Segments are effectively a way for Unleash users to define a list of constraints in such a way that makes them reusable across toggles without manually copying the constraint across to another toggle. Segments have two modes of operation, from the SDK's perspective, the inline mode will have no impact, segments will be remapped on the server side into constraints on the toggle information, no changes need to be . The second mode, global segments, requires that the SDK both opt in and handle the response differently. The handling should effectively result in unpacking the segments referenced in the feature strategies into a set of constraints. The changes required are described below.

Solution suggestions

Control Header

The SDK needs to pass up a Unleash-Client-Spec header with a semver value greater or equal to 4.2.0 (i.e. be greater or equal to the version of the unleash client spec tests where global segments are described) when hitting the get toggles endpoint on the Unleash server. This will enable the Unleash server to respond with the enhanced format

Example of the difference between enhanced and standard format:

Standard Format (default)

{
   "version": 2,
   "features": [  
       {
           "strategies": [
               {
                   "name": "flexibleRollout",
                   "constraints": [
                       {
                           "values": [
                               "31"
                           ],
                           "inverted": false,
                           "operator": "IN",
                           "contextName": "appName",
                           "caseInsensitive": false
                       }
                   ],          
                   "parameters": {
                       "groupId": "Test1",
                       "rollout": "100",
                       "stickiness": "default"
                   }
               }
           ],
           "name": "Test1"
       },
       {
           "strategies": [
               {
                   "name": "flexibleRollout",
                   "constraints": [
                       {
                           "values": [
                               "31"
                           ],
                           "inverted": false,
                           "operator": "IN",
                           "contextName": "appName",
                           "caseInsensitive": false
                       }
                   ],          
                   "parameters": {
                       "groupId": "Test2",
                       "rollout": "100",
                       "stickiness": "default"
                   }
               }
           ],
           "name": "Test2"
       }    
   ],
   "query": {
       "environment": "default"
   }
}

Enhanced Format (requires opt in)

{
   "version": 2,
   "features": [   
       {
           "strategies": [
               {
                   "name": "flexibleRollout",
                   "constraints": [],
                   "parameters": {
                       "groupId": "Test1",
                       "rollout": "100",
                       "stickiness": "default"
                   },
                   "segments": [
                       1
                   ]
               }
           ],
           "name": "Test1"
       },
       {
           "strategies": [
               {
                   "name": "flexibleRollout",
                   "constraints": [],
                   "parameters": {
                       "groupId": "Test2",
                       "rollout": "100",
                       "stickiness": "default"
                   },
                   "segments": [
                       1
                   ]
               }
           ],
           "name": "Test2"
       }     
   ],
   "query": {
       "environment": "default"
   },
   "segments": [
       {
           "id": 1,           
           "constraints": [
               {
                   "values": [
                       "31"
                   ],
                   "inverted": false,
                   "operator": "IN",
                   "contextName": "appName",
                   "caseInsensitive": false
               }
           ]           
       }
   ]
}

The relevant changes between the two formats are that in the enhanced format the segments are defined once as a global list and referenced within the strategy on the toggle by its ID. What's important to note is that the two above packets should be handled identically, they reference the same toggle state.

Considerations

rbtcollins commented 2 years ago

Yes, I think the rust SDK should support everything eventually. Right now I'm trying to work up the versions one by one :)