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

FeatureRepository class for networking #18

Merged
merged 46 commits into from
May 8, 2023
Merged

FeatureRepository class for networking #18

merged 46 commits into from
May 8, 2023

Conversation

tinahollygb
Copy link
Contributor

@tinahollygb tinahollygb commented Apr 27, 2023

These changes add a new class FeatureRepository allowing users to fetch features for creating the Context instance.

Closes #13

Dependencies

Here are the available methods (other than the constructor):

  • #fetch returns nil if it fails. Nil features passed to the context will be ignored.
  • #fetch! throws an exception if it fails
  • #features_json returns the parsed features JSON. Useful if you need to call it several times but don't want to make a network request each time.

Sometimes developers prefer to raise and rescue, while others may prefer nil, depending on how they'd like to do it, e.g. fall back to not using GrowthBook, or handle an error differently.

Here's an example of both and the results of each in the Ruby console:

irb(main):017:1* Growthbook::FeatureRepository.new(
irb(main):018:1*   endpoint: 'https://cdn.growthbook.io/api/features/some-invalid-key',
irb(main):019:1*   decryption_key: nil
irb(main):020:0> ).fetch
=> nil
irb(main):021:1* Growthbook::FeatureRepository.new(
irb(main):022:1*   endpoint: 'https://cdn.growthbook.io/api/features/some-invalid-key',
irb(main):023:1*   decryption_key: nil
irb(main):024:0> ).fetch!
/Users/tina/Documents/code/growthbook/growthbook-ruby/lib/growthbook/feature_repository.rb:44:in `fetch!': Growthbook::FeatureRepository::FeatureFetchError (Growthbook::FeatureRepository::FeatureFetchError)
	from (irb):24:in `<main>'

In the case of nil features, when they go to use the SDK, it'll return the fallback value if provided:

irb(main):015:0> gb
=>
#<Growthbook::Context:0x0000000105f1f3a0
 @attributes={"country"=>"france"},
 @enabled=true,
 @features={},
 @forced_features={},
 @forced_variations={},
 @impressions={}>
irb(main):016:0>
irb(main):017:0> gb.feature_value(:greeting, 'fallback')
=> "fallback"
irb(main):018:0>

For details about the exceptions thrown and possible failure cases, see tests.

You can manually test this class by executing bundle exec irb and copy pasting the following code:

Plain text features example

require 'growthbook'

# Create a feature repository instance
features_repository = Growthbook::FeatureRepository.new(
  endpoint: 'https://cdn.growthbook.io/api/features/java_NsrWldWd5bxQJZftGsWKl7R2yD2LtAK8C8EUYh9L8',
  decryption_key: nil
)

# Fetch the features - This one will return nil
features = features_repository.fetch
# You can also fetch the features with fetch! which will throw an exception if anything fails
# features = features_repository.fetch!

gb = Growthbook::Context.new({ features: features, attributes: { country: 'france' } })

gb.feature_value(:banner_text)

This is the result:

image

Encrypted features example

require 'growthbook'

# Create a feature repository instance
features_repository = Growthbook::FeatureRepository.new(
  endpoint: 'https://cdn.growthbook.io/api/features/sdk-862b5mHcP9XPugqD',
  decryption_key: 'BhB1wORFmZLTDjbvstvS8w=='
)

# Fetch the features - This one will return nil
features = features_repository.fetch
# You can also fetch the features with fetch! which will throw an exception if anything fails
# features = features_repository.fetch!

gb = Growthbook::Context.new({ features: features, attributes: { country: 'france' } })

gb.feature_value(:greeting)

This is the result:

image

FeatureRepository test cases
Growthbook::FeatureRepository
  .initialize
    endpoint
      is expected to eq "https://cdn.growthbook.io/api/features/key-abc123"
    decryption_key
      is expected to be nil
    when provided a decryption key
      endpoint
        is expected to eq "https://cdn.growthbook.io/api/features/key-abc123"
      decryption_key
        is expected to eq "some-key"
  #fetch
    when not using a decryption key
      returns parsed JSON from the response features
      when provided a misconfigured URL
        is expected to be nil
      when the network request fails
        is expected to be nil
      when the parsing fails
        is expected to be nil
    when provided a decryption key
      returns decrypted parsed JSON from the response encryptedFeatures
      when the network request fails
        is expected to be nil
      when the parsing fails
        is expected to be nil
      when the decryption fails
        is expected to be nil
  #fetch!
    when provided a misconfigured URL
      raises a FeatureFetchError
    when not using a decryption key
      returns parsed JSON from the response features
      when the network request fails
        raises a FeatureFetchError
      when the parsing fails
        raises a FeatureParseError
    when provided a decryption key
      returns decrypted parsed JSON from the response encryptedFeatures
      when the network request fails
        raises a FeatureFetchError
      when the parsing fails
        raises a FeatureParseError
      when the decryption fails
        raises a FeatureParseError

Next steps

  • Update the Rails example to use this networking class
  • Update the documentation to include implementation details for networking

@tinahollygb tinahollygb marked this pull request as ready for review April 27, 2023 17:33
@tinahollygb tinahollygb requested a review from jdorn April 27, 2023 17:34
@tinahollygb tinahollygb merged commit 862e291 into main May 8, 2023
@tinahollygb tinahollygb deleted the sdk-networking branch May 8, 2023 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for networking, refreshing, and caching
2 participants