Closed AlexsJones closed 2 years ago
By generating the Kubernetes CRD, we could consume that in Open Feature Operator.
Here is an example of converting this to cue
#Spec: {
// flagd Flag Configuration
//
// Defines flags for use in flagd, including typed variants and
// rules
@jsonschema(schema="http://json-schema.org/draft-07/schema#")
flags?: {
{[=~"^.{1,}$" & !~"^()$"]: #booleanFlag | #stringFlag | #numberFlag | #objectFlag}
}
#flag: null | bool | number | string | [...] | {
// Indicates whether the flag is functional. Disabled flags are
// treated as if they don't exist
state: "ENABLED" | "DISABLED"
// Default variant
//
// The variant to serve if no dynamic targeting applies
defaultVariant: string
// Targeting Logic
//
// JsonLogic expressions to be used for dynamic evaluation. The
// "context" is passed as the data. Rules must resolve one of the
// defined variants, or the "defaultVariant" will be used.
targeting?: {
...
}
...
}
#booleanVariants: {
variants?: null | bool | number | string | [...] | {
{[=~"^.{1,}$" & !~"^()$"]: bool}
} | *{
on: true
off: false
...
}
...
}
#stringVariants: {
variants?: null | bool | number | string | [...] | {
{[=~"^.{1,}$" & !~"^()$"]: string}
}
...
}
#numberVariants: {
variants?: null | bool | number | string | [...] | {
{[=~"^.{1,}$" & !~"^()$"]: number}
}
...
}
#objectVariants: {
variants?: null | bool | number | string | [...] | {
{[=~"^.{1,}$" & !~"^()$"]: {
...
}}
}
...
}
#$comment: _
#booleanFlag: #flag & #booleanVariants
#stringFlag: #flag & #stringVariants
#numberFlag: #flag & #numberVariants
#objectFlag: #flag & #objectVariants
...
}
flags: #Spec & {
myBoolFlag: {
state: "ENABLED", variants: {
on: true
off: false
}
defaultVariant: "on"
}
myStringFlag: {
state: "ENABLED", variants: {
key1: "val1", key2: "val2"
}
defaultVariant: "key1"
}
myNumberFlag: {
state: "ENABLED", variants: {
one: 1
two: 2
}
defaultVariant: "two"
}
myObjectFlag: {
state: "ENABLED", variants: {
object1: key: "val", object2: key: true
}
defaultVariant: "object1"
}
}
back into json...
{
"flags": {
"myBoolFlag": {
"state": "ENABLED",
"variants": {
"on": true,
"off": false
},
"defaultVariant": "on"
},
"myStringFlag": {
"state": "ENABLED",
"variants": {
"key1": "val1",
"key2": "val2"
},
"defaultVariant": "key1"
},
"myNumberFlag": {
"state": "ENABLED",
"variants": {
"one": 1,
"two": 2
},
"defaultVariant": "two"
},
"myObjectFlag": {
"state": "ENABLED",
"variants": {
"object1": {
"key": "val"
},
"object2": {
"key": true
}
},
"defaultVariant": "object1"
}
}
}
https://github.com/open-feature/research/blob/main/003-OFEP-CUE-upstream.md
This will be closed and reopened as a PR against the CUE state
As flagD evolves, it will be presented on different types of services with a variety of protocols. Many of these protocols have client libraries that can be generated for convenience. For example, we use openapi to enable us to create a golang server implementation. This is great because a) it's fast and easy b) it matches the specification files promises exactly - validation/matching for free.
Given we are looking to now expand to offer new generated server support for gRPC, we are in a predicament about whether to a) derive the implementation from OpenAPI b) have a new source of truth as .proto files c) have some sort of composite between the two.
My proposal here would be to choose a new top-level DSL to define the specifications required to drive generated server code implementations. As such, cue offers integration with YAML/JSON & protobuf directly. This would mean we could use a single file(s) and toolchain to generate all of the automatically created code for flagD. The benefit here would be a single source of truth, ease of contribution, ease of extension and simplified build process.
By switching to CUE, we can use a single build chain to produce the OpenAPI spec as a generated file that is convenient to users who want to build against flagD ( possible code-generating their own client libraries). Though we would not need to use the generated OpenAPI spec through any further generator. Instead, the protoc-http tool will allow for generation from protobuf files as per @James-Milligan initial investigation.
Next steps:
If we have agreement on this, I would propose looking at a top level CUE file(s) to replace the current OpenAPI YAML file that is generated from. At this point we will be able to prove it can become the new top-of-chain build step, enabling us to then replace the downstream components.