Website | Documentation | Issues | Contributing |
This repository is a port of the Featurevisor JavaScript SDK to Swift.
The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift
compiler.
Once you have your Swift package set up, adding Featurevisor as a dependency is as easy as adding it to the dependencies
value of your Package.swift
.
dependencies: [
.package(url: "https://github.com/featurevisor/featurevisor-swift.git", .upToNextMajor(from: "X.Y.Z"))
]
We would like to be able to set up the Featurevisor SDK instance once and reuse the same instance everywhere.
The SDK can be initialized in two different ways depending on your needs.
You can fetch the datafile content on your own and just pass it via options.
import FeaturevisorSDK
let datafileContent: DatafileContent = ...
var options: InstanceOptions = .default
options.datafile = datafileContent
let f = try createInstance(options: options)
If you want to delegate the responsibility of fetching the datafile to the SDK.
import FeaturevisorSDK
var options: InstanceOptions = .default
options.datafileUrl = "https://cdn.yoursite.com/production/datafile-tag-all.json"
let f = try createInstance(options: options)
If you need to take further control on how the datafile is fetched, you can pass a custom handleDatafileFetch
function
public typealias DatafileFetchHandler = (_ datafileUrl: String) -> Result<DatafileContent, Error>
import FeaturevisorSDK
var options: InstanceOptions = .default
options.handleDatafileFetch = { datafileUrl in
// you need to return here Result<DatafileContent, Error>
}
let f = try createInstance(options: options)
Contexts are a set of attribute values that we pass to SDK for evaluating features.
They are objects where keys are the attribute keys, and values are the attribute values.
public enum AttributeValue {
case string(String)
case integer(Int)
case double(Double)
case boolean(Bool)
case date(Date)
let context = [
"myAttributeKey": .string("myStringAttributeValue"),
"anotherAttributeKey": .double(0.999),
]
Once the SDK is initialized, you can check if a feature is enabled or not:
let featureKey = "my_feature";
let context = [
"userId": .string("123"),
"country": .string("nl")
]
let isEnabled = f.isEnabled(featureKey: featureKey, context: context)
If your feature has any variations defined, you can get evaluate them as follows
let featureKey = "my_feature";
let context = [
"userId": .string("123")
]
let variation = f.getVariation(featureKey: featureKey, context: context)
let featureKey = "my_feature";
let variableKey = "color"
let context = [
"userId": .string("123")
]
let variable: VariableValue? = f.getVariable(featureKey: featureKey, variableKey: variableKey, context: context)
let booleanVariable: Bool? = f.getVariableBoolean(featureKey: FeatureKey, variableKey: VariableKey, context: Context)
let stringVariable: String? = f.getVariableString(featureKey: FeatureKey, variableKey: VariableKey, context: Context)
let integerVariable: Int? = f.getVariableInteger(featureKey: FeatureKey, variableKey: VariableKey, context: Context)
let doubleVariable: Double? = f.getVariableDouble(featureKey: FeatureKey, variableKey: VariableKey, context: Context)
let arrayVariable: [String]? = f.getVariableArray(featureKey: FeatureKey, variableKey: VariableKey, context: Context)
let objectVariable: MyDecodableObject? = f.getVariableObject(featureKey: FeatureKey, variableKey: VariableKey, context: Context)
let jsonVariable: MyJSONDecodableObject? = f.getVariableJSON(featureKey: FeatureKey, variableKey: VariableKey, context: Context)
By default, Featurevisor will log logs in console output window for warn
and error
levels.
let logger = createLogger(levels: [.error, .warn, .info, .debug])
let logger = createLogger(
levels: [.error, .warn, .info, .debug],
handle: { level, message, details in ... })
var options = InstanceOptions.default
options.logger = logger
let f = try createInstance(options: options)
Refreshing the datafile is convenient when you want to update the datafile in runtime, for example when you want to update the feature variations and variables config without having to restart your application.
It is only possible to refresh datafile in Featurevisor if you are using the datafileUrl option when creating your SDK instance.
f.refresh()
If you want to refresh your datafile every X number of seconds, you can pass the refreshInterval
option when creating your SDK instance:
import FeaturevisorSDK
var options: InstanceOptions = .default
options.datafileUrl = "https://cdn.yoursite.com/production/datafile-tag-all.json"
options.refreshInterval = 30 // 30 seconds
let f = try createInstance(options: options)
You can stop the interval by calling
f.stopRefreshing()
If you want to resume refreshing
f.startRefreshing()
Every successful refresh will trigger the onRefresh
option
import FeaturevisorSDK
var options: InstanceOptions = .default
options.datafileUrl = "https://cdn.yoursite.com/production/datafile-tag-all.json"
options.onRefresh = { ... }
let f = try createInstance(options: options)
Not every refresh is going to be of a new datafile version. If you want to know if datafile content has changed in any particular refresh, you can listen to onUpdate
option
import FeaturevisorSDK
var options: InstanceOptions = .default
options.datafileUrl = "https://cdn.yoursite.com/production/datafile-tag-all.json"
options.onUpdate = { ... }
let f = try createInstance(options: options)
Featurevisor SDK implements a simple event emitter that allows you to listen to events that happen in the runtime.
You can listen to these events that can occur at various stages in your application
When the SDK is ready to be used if used in an asynchronous way involving datafileUrl option
import FeaturevisorSDK
var options: InstanceOptions = .default
options.datafileUrl = "https://cdn.yoursite.com/production/datafile-tag-all.json"
options.onReady = { ... }
let f = try createInstance(options: options)
You can also synchronously check if the SDK is ready
guard f.isReady() else {
// sdk is not ready to be used
}
When a feature is activated
import FeaturevisorSDK
var options: InstanceOptions = .default
options.datafileUrl = "https://cdn.yoursite.com/production/datafile-tag-all.json"
options.onActivation = { ... }
let f = try createInstance(options: options)
To install it locally use below commands. Note, we use featurevisor-swift to avoid conflicts with other Featurevisor CLIs
$ cd path/to/featurevisor-swift-sdk
$ swift build -c release
$ cd .build/release
$ cp -f Featurevisor /usr/local/bin/featurevisor-swift
Now you can usage like below:
$ cd path/to/featurevisor-project-with-yamls
$ featurevisor-swift test .
To install via Swift Package Manager, you need to add it as a dependency under your Package.swift
file , where X.X.X
is the version which you want to use.
dependencies: [
.package(
url: "https://github.com/featurevisor/featurevisor-swift",
exact: "X.X.X"
)
]
To run use below command:
$ swift run featurevisor test .
To update the swift's featurevisor use below command:
$ swift package update
If you would like to test your feature/s setup against Swift SDK you can do this by invoking the below command.
Currently, it takes all features which are being supported by ios
and tvos
and run tests for them.
$ swift run featurevisor test .
'only-failures'
If you are interested to see only the test specs that fail:
Example command:
$ swift run featurevisor test --only-failures .
You can measure how fast or slow your SDK evaluations are for particular features.
The --n
option is used to specify the number of iterations to run the benchmark for.
To benchmark evaluating a feature itself if it is enabled or disabled via SDK's .isEnabled()
method:
featurevisor-swift benchmark \
--environment staging \
--feature feature_key \
--context '{"user_id":"123"}' \
-n 100
To benchmark evaluating a feature's variation via SDKs's .getVariation()
method:
featurevisor-swift benchmark \
--environment staging \
--feature feature_key \
--context '{"user_id":"123"}' \
--variation \
-n 100
To benchmark evaluating a feature's variable via SDKs's .getVariable()
method:
featurevisor-swift benchmark \
--environment staging \
--feature feature_key \
--variable variable_key \
--context '{"user_id":"123"}' \
-n 100
To learn why certain values (like feature and its variation or variables) are evaluated as they are against provided context:
featurevisor-swift evaluate \
--environment staging \
--feature feature_key \
--context '{"user_id":"123"}' \
This will show you full evaluation details helping you debug better in case of any confusion. It is similar to logging in SDKs with debug level. But here instead, we are doing it at CLI directly in our Featurevisor project without having to involve our application(s).