Skip to content

Commit

Permalink
add IsVisible field / interface method
Browse files Browse the repository at this point in the history
  • Loading branch information
ccbrown committed Mar 5, 2024
1 parent c289cff commit 57d1c2d
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 1 deletion.
12 changes: 12 additions & 0 deletions graphql/schema/enum_type.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package schema

import (
"context"
"fmt"

"github.com/ccbrown/api-fu/graphql/ast"
Expand All @@ -11,6 +12,10 @@ type EnumType struct {
Description string
Directives []*Directive
Values map[string]*EnumValueDefinition

// If given, this type will only be visible via introspection if the given function returns
// true. This can for example be used to build APIs that are gated behind feature flags.
IsVisible func(context.Context) bool
}

type EnumValueDefinition struct {
Expand Down Expand Up @@ -44,6 +49,13 @@ func (t *EnumType) TypeName() string {
return t.Name
}

func (t *EnumType) IsTypeVisible(ctx context.Context) bool {
if t.IsVisible == nil {
return true
}
return t.IsVisible(ctx)
}

func (t *EnumType) shallowValidate() error {
if len(t.Values) == 0 {
return fmt.Errorf("%v must have at least one field", t.Name)
Expand Down
4 changes: 4 additions & 0 deletions graphql/schema/field_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ type FieldDefinition struct {
Directives []*Directive
DeprecationReason string

// If given, this field will only be visible and usable if the given function returns true. This
// can for example be used to build APIs that are gated behind feature flags.
IsVisible func(context.Context) bool

// This function can be used to define the cost of resolving the field. The total cost of an
// operation can be calculated before the operation is executed, enabling rate limiting and
// metering.
Expand Down
12 changes: 12 additions & 0 deletions graphql/schema/input_object_type.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package schema

import (
"context"
"fmt"
"strings"

Expand All @@ -25,6 +26,10 @@ type InputObjectType struct {
// For most use-cases, this function is optional. If it is required, but nil, you will get an
// error when you attempt to create the schema.
ResultCoercion func(interface{}) (map[string]interface{}, error)

// If given, this type will only be visible via introspection if the given function returns
// true. This can for example be used to build APIs that are gated behind feature flags.
IsVisible func(context.Context) bool
}

func (t *InputObjectType) String() string {
Expand All @@ -51,6 +56,13 @@ func (t *InputObjectType) TypeName() string {
return t.Name
}

func (t *InputObjectType) IsTypeVisible(ctx context.Context) bool {
if t.IsVisible == nil {
return true
}
return t.IsVisible(ctx)
}

func (t *InputObjectType) CoerceVariableValue(v interface{}) (interface{}, error) {
result := map[string]interface{}{}

Expand Down
12 changes: 12 additions & 0 deletions graphql/schema/interface_type.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package schema

import (
"context"
"fmt"
"strings"
)
Expand All @@ -10,6 +11,10 @@ type InterfaceType struct {
Description string
Directives []*Directive
Fields map[string]*FieldDefinition

// If given, this type will only be visible via introspection if the given function returns
// true. This can for example be used to build APIs that are gated behind feature flags.
IsVisible func(context.Context) bool
}

func (t *InterfaceType) String() string {
Expand All @@ -36,6 +41,13 @@ func (t *InterfaceType) TypeName() string {
return t.Name
}

func (t *InterfaceType) IsTypeVisible(ctx context.Context) bool {
if t.IsVisible == nil {
return true
}
return t.IsVisible(ctx)
}

func (t *InterfaceType) shallowValidate() error {
if len(t.Fields) == 0 {
return fmt.Errorf("%v must have at least one field", t.Name)
Expand Down
12 changes: 12 additions & 0 deletions graphql/schema/object_type.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package schema

import (
"context"
"fmt"
"strings"
)
Expand All @@ -16,6 +17,10 @@ type ObjectType struct {
// Objects that implement one or more interfaces must define this. The function should return
// true if obj is an object of this type.
IsTypeOf func(obj interface{}) bool

// If given, this type will only be visible via introspection if the given function returns
// true. This can for example be used to build APIs that are gated behind feature flags.
IsVisible func(context.Context) bool
}

func (t *ObjectType) String() string {
Expand Down Expand Up @@ -57,6 +62,13 @@ func (t *ObjectType) TypeName() string {
return t.Name
}

func (t *ObjectType) IsTypeVisible(ctx context.Context) bool {
if t.IsVisible == nil {
return true
}
return t.IsVisible(ctx)
}

func (t *ObjectType) satisfyInterface(iface *InterfaceType) error {
for name, ifaceField := range iface.Fields {
field, ok := t.Fields[name]
Expand Down
12 changes: 12 additions & 0 deletions graphql/schema/scalar_type.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package schema

import (
"context"
"fmt"

"github.com/ccbrown/api-fu/graphql/ast"
Expand All @@ -20,6 +21,10 @@ type ScalarType struct {
// Should return nil if coercion is impossible. In many cases, this can be the same as
// VariableValueCoercion.
ResultCoercion func(interface{}) interface{}

// If given, this type will only be visible via introspection if the given function returns
// true. This can for example be used to build APIs that are gated behind feature flags.
IsVisible func(context.Context) bool
}

func (t *ScalarType) String() string {
Expand All @@ -46,6 +51,13 @@ func (t *ScalarType) TypeName() string {
return t.Name
}

func (t *ScalarType) IsTypeVisible(ctx context.Context) bool {
if t.IsVisible == nil {
return true
}
return t.IsVisible(ctx)
}

func (t *ScalarType) CoerceVariableValue(v interface{}) (interface{}, error) {
if coerced := t.VariableValueCoercion(v); coerced != nil {
return coerced, nil
Expand Down
2 changes: 2 additions & 0 deletions graphql/schema/schema.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package schema

import (
"context"
"fmt"
"regexp"
"strings"
Expand Down Expand Up @@ -147,6 +148,7 @@ type Type interface {
type NamedType interface {
Type
TypeName() string
IsTypeVisible(context.Context) bool
}

type WrappedType interface {
Expand Down
16 changes: 15 additions & 1 deletion graphql/schema/union_type.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package schema

import "fmt"
import (
"context"
"fmt"
)

type UnionType struct {
Name string
Description string
Directives []*Directive
MemberTypes []*ObjectType

// If given, this type will only be visible via introspection if the given function returns
// true. This can for example be used to build APIs that are gated behind feature flags.
IsVisible func(context.Context) bool
}

func (d *UnionType) String() string {
Expand All @@ -33,6 +40,13 @@ func (d *UnionType) TypeName() string {
return d.Name
}

func (t *UnionType) IsTypeVisible(ctx context.Context) bool {
if t.IsVisible == nil {
return true
}
return t.IsVisible(ctx)
}

func (d *UnionType) shallowValidate() error {
if len(d.MemberTypes) == 0 {
return fmt.Errorf("%v must have at least one member type", d.Name)
Expand Down

0 comments on commit 57d1c2d

Please sign in to comment.