https://github.com/abramisola/wave
A Go Programming Language Feature Flagging Library
https://github.com/abramisola/wave
authorization feature-flags go golang golang-library
Last synced: 25 days ago
JSON representation
A Go Programming Language Feature Flagging Library
- Host: GitHub
- URL: https://github.com/abramisola/wave
- Owner: abramisola
- License: mit
- Created: 2017-04-25T22:09:11.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2017-04-27T04:30:23.000Z (about 9 years ago)
- Last Synced: 2024-12-22T08:52:17.776Z (over 1 year ago)
- Topics: authorization, feature-flags, go, golang, golang-library
- Language: Go
- Size: 32.2 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Wave
====
Go programming language feature flagging
[](https://godoc.org/github.com/aisola/wave)
[](https://travis-ci.org/aisola/wave)
[](https://coveralls.io/github/aisola/wave?branch=master)
[](https://codeclimate.com/github/aisola/wave)
[](https://goreportcard.com/report/github.com/aisola/wave)
[](http://opensource.org/licenses/MIT)
Inspired by the [pyrollout](https://github.com/brechin/pyrollout) python
package by [Jason Brechin](https://github.com/brechin). I've put no genius
into this. I've just ported it and made it slightly more go idiomatic.
I've renamed it from rollout to wave simply because I am lazy and do not want
to type `rollout` so many times in my go code. Wave is shorter and ebbs and
flows like a software rollout too.
## Installation & Tests
Using good ol' `go get`:
```bash
go get -u -v github.com/aisola/wave
go test github.com/aisola/wave/...
```
Using the new fangled `dep`:
```bash
dep ensure -update github.com/aisola/wave
go test github.com/aisola/wave/...
```
## Typical Usage
While wave allows you to create and manage your own wave instances, the typical
user of wave will simply underscore-import a backend and use the default instance.
Here, since we are not underscore-importing ay different backend, wave uses
in-memory storage.
```go
// ...
import (
"github.com/aisola/wave"
)
func main() {
// ...
}
```
If you want undefined features grant access to all users, you can do that by
marking the default `Wave.UndefinedAccess` field as `true`.
```go
wave.Default.UndefinedAccess = true
```
Now add features:
```go
// ...
// Open to all by using the special group 'ALL'
wave.AddFeature(wave.NewFeatureGroups("feature_for_all", wave.ALL))
// Open to select groups
wave.AddFeature(wave.NewFeatureGroups("feature_for_groups", []string{"vip", "early-adopter"}))
// Open to specific user(s), by user ID
wave.AddFeature(wave.NewFeatureUsers("feature_for_users", []string{"123", "456", "789"}))
// ...
```
Check access to features:
```go
// ...
func UntestedFeature(user wave.User) bool {
// Because this feature was not defined, access will always be denied, unless you've
// set Wave.UndefinedAccess as true.
if !wave.Can(user, "use_untested_feature") {
return false
}
DoSomethingCool()
return true
}
func FooHandler(w http.ResponseWriter, r *http.Request) {
// The user type that we get from the request context is one passed in by
// an authentication middleware of sorts. This user object should implement
// the wave.User interface.
ctx := r.Context()
user := ctx.Value("user").(*User)
if !wave.Can(user, "feature_for_users") {
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
return
}
DoSomethingElseCoolHere(w)
}
// ...
```
## Creating multiple Wave instances
In some cases, you may want to create and use more than one instance of wave in
your application. For instance, if you have two different APIs serving out of
the same binary.
```go
import (
"github.com/aisola/wave"
_ "github.com/some/wave/backend"
)
// ...
api1 := wave.NewWave("backend")
api2 := wave.NewWave("backend")
if err := api1.Open("backend://username:password@127.0.0.1:8000/api1"); err != nil {
log.Fatalf("Could not open up wave backend for api1, %s", err)
}
defer api1.Close()
if err := api2.Open("backend://username:password@127.0.0.1:8000/api2"); err != nil {
log.Fatalf("Could not open up wave backend for api2, %s", err)
}
defer api2.Close()
// Open to all by using the special group 'ALL'
api1.AddFeature(wave.NewFeatureGroups("feature_for_all", wave.ALL))
// Open to admins
api2.AddFeature(wave.NewFeatureGroups("feature_for_admins", []string{"admins"}))
// ...
```