github.com/TykTechnologies/tyk/internal/graphengine
No package summary is available.
Package
Files: 11. Third party imports: 4. Imports from organisation: 15. Tests: 0. Benchmarks: 0.
Constants
const (
ComplexityFailReasonNone ComplexityFailReason = iota
ComplexityFailReasonInternalError
ComplexityFailReasonDepthLimitExceeded
)
const (
GranularAccessFailReasonNone GranularAccessFailReason = iota
GranularAccessFailReasonInternalError
GranularAccessFailReasonValidationError
GranularAccessFailReasonIntrospectionDisabled
)
const (
ReverseProxyTypeNone ReverseProxyType = iota
ReverseProxyTypeIntrospection
ReverseProxyTypeWebsocketUpgrade
ReverseProxyTypeGraphEngine
ReverseProxyTypePreFlight
)
const (
GraphQLEngineTransportTypeProxyOnly GraphQLEngineTransportType = iota
GraphQLEngineTransportTypeMultiUpstream
)
const (
EngineVersionUnknown EngineVersion = iota
EngineVersionV1
EngineVersionV2
EngineVersionV3
)
const (
HTTPJSONDataSource = "HTTPJSONDataSource"
GraphQLDataSource = "GraphQLDataSource"
SchemaDataSource = "SchemaDataSource"
TykRESTDataSource = "TykRESTDataSource"
TykGraphQLDataSource = "TykGraphQLDataSource"
)
Vars
var (
ProxyingRequestFailedErr = errors.New("there was a problem proxying the request")
errCustomBodyResponse = errors.New("errCustomBodyResponse")
GraphQLDepthLimitExceededErr = errors.New("depth limit exceeded")
ErrIntrospectionDisabled = errors.New("introspection is disabled")
ErrUnknownReverseProxyType = errors.New("unknown reverse proxy type")
)
Interface Guard
var _ Engine = (*EngineV1)(nil)
var graphqlProxyContextInfo = contextKey{}
Types
ComplexityAccessDefinition
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| Limit |
|
No comment on field. |
| FieldAccessRights |
|
No comment on field. |
type ComplexityAccessDefinition struct {
Limit ComplexityLimit
FieldAccessRights []ComplexityFieldAccessDefinition
}
ComplexityChecker
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type ComplexityChecker interface {
DepthLimitExceeded(r *http.Request, accessDefinition *ComplexityAccessDefinition) ComplexityFailReason
}
ComplexityFailReason
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type ComplexityFailReason int
ComplexityFieldAccessDefinition
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| TypeName |
|
No comment on field. |
| FieldName |
|
No comment on field. |
| Limits |
|
No comment on field. |
type ComplexityFieldAccessDefinition struct {
TypeName string
FieldName string
Limits ComplexityFieldLimits
}
ComplexityFieldLimits
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| MaxQueryDepth |
|
No comment on field. |
type ComplexityFieldLimits struct {
MaxQueryDepth int
}
ComplexityLimit
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| MaxQueryDepth |
|
No comment on field. |
type ComplexityLimit struct {
MaxQueryDepth int
}
ContextRetrieveRequestV1Func
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type ContextRetrieveRequestV1Func func(r *http.Request) *graphql.Request
ContextRetrieveRequestV2Func
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type ContextRetrieveRequestV2Func func(r *http.Request) *graphqlv2.Request
ContextStoreRequestV1Func
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type ContextStoreRequestV1Func func(r *http.Request, gqlRequest *graphql.Request)
ContextStoreRequestV2Func
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type ContextStoreRequestV2Func func(r *http.Request, gqlRequest *graphqlv2.Request)
Engine
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type Engine interface {
Version() EngineVersion
HasSchema() bool
Cancel()
ProcessAndStoreGraphQLRequest(w http.ResponseWriter, r *http.Request) (err error, statusCode int)
ProcessGraphQLComplexity(r *http.Request, accessDefinition *ComplexityAccessDefinition) (err error, statusCode int)
ProcessGraphQLGranularAccess(w http.ResponseWriter, r *http.Request, accessDefinition *GranularAccessDefinition) (err error, statusCode int)
HandleReverseProxy(params ReverseProxyParams) (res *http.Response, hijacked bool, err error)
}
EngineV1
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| ExecutionEngine |
|
No comment on field. |
| Schema |
|
No comment on field. |
| ApiDefinition |
|
No comment on field. |
| HttpClient |
|
No comment on field. |
| logger |
|
No comment on field. |
| gqlTools |
|
No comment on field. |
| graphqlRequestProcessor |
|
No comment on field. |
| complexityChecker |
|
No comment on field. |
| granularAccessChecker |
|
No comment on field. |
| reverseProxyPreHandler |
|
No comment on field. |
| ctxStoreRequestFunc |
|
No comment on field. |
| ctxRetrieveRequestFunc |
|
No comment on field. |
| newReusableBodyReadCloser |
|
No comment on field. |
type EngineV1 struct {
ExecutionEngine *graphql.ExecutionEngine
Schema *graphql.Schema
ApiDefinition *apidef.APIDefinition
HttpClient *http.Client
logger abstractlogger.Logger
gqlTools graphqlGoToolsV1
graphqlRequestProcessor GraphQLRequestProcessor
complexityChecker ComplexityChecker
granularAccessChecker GranularAccessChecker
reverseProxyPreHandler ReverseProxyPreHandler
ctxStoreRequestFunc func(r *http.Request, gqlRequest *graphql.Request)
ctxRetrieveRequestFunc func(r *http.Request) *graphql.Request
newReusableBodyReadCloser NewReusableBodyReadCloserFunc
}
EngineV1Injections
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| PreSendHttpHook |
|
No comment on field. |
| PostReceiveHttpHook |
|
No comment on field. |
| ContextStoreRequest |
|
No comment on field. |
| ContextRetrieveRequest |
|
No comment on field. |
| NewReusableBodyReadCloser |
|
No comment on field. |
type EngineV1Injections struct {
PreSendHttpHook datasource.PreSendHttpHook
PostReceiveHttpHook datasource.PostReceiveHttpHook
ContextStoreRequest ContextStoreRequestV1Func
ContextRetrieveRequest ContextRetrieveRequestV1Func
NewReusableBodyReadCloser NewReusableBodyReadCloserFunc
}
EngineV1Options
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| Logger |
|
No comment on field. |
| ApiDefinition |
|
No comment on field. |
| Schema |
|
No comment on field. |
| HttpClient |
|
No comment on field. |
| Injections |
|
No comment on field. |
type EngineV1Options struct {
Logger *logrus.Logger
ApiDefinition *apidef.APIDefinition
Schema *graphql.Schema
HttpClient *http.Client
Injections EngineV1Injections
}
EngineV2
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| ExecutionEngine |
|
No comment on field. |
| Schema |
|
No comment on field. |
| ApiDefinition |
|
No comment on field. |
| HttpClient |
|
No comment on field. |
| StreamingClient |
|
No comment on field. |
| OpenTelemetry |
|
No comment on field. |
| logger |
|
No comment on field. |
| gqlTools |
|
No comment on field. |
| graphqlRequestProcessor |
|
No comment on field. |
| complexityChecker |
|
No comment on field. |
| granularAccessChecker |
|
No comment on field. |
| reverseProxyPreHandler |
|
No comment on field. |
| contextCancel |
|
No comment on field. |
| beforeFetchHook |
|
No comment on field. |
| afterFetchHook |
|
No comment on field. |
| ctxStoreRequestFunc |
|
No comment on field. |
| ctxRetrieveRequestFunc |
|
No comment on field. |
| newReusableBodyReadCloser |
|
No comment on field. |
| seekReadCloser |
|
No comment on field. |
| tykVariableReplacer |
|
No comment on field. |
type EngineV2 struct {
ExecutionEngine *graphql.ExecutionEngineV2
Schema *graphql.Schema
ApiDefinition *apidef.APIDefinition
HttpClient *http.Client
StreamingClient *http.Client
OpenTelemetry *EngineV2OTelConfig
logger abstractlogger.Logger
gqlTools graphqlGoToolsV1
graphqlRequestProcessor GraphQLRequestProcessor
complexityChecker ComplexityChecker
granularAccessChecker GranularAccessChecker
reverseProxyPreHandler ReverseProxyPreHandler
contextCancel context.CancelFunc
beforeFetchHook resolve.BeforeFetchHook
afterFetchHook resolve.AfterFetchHook
ctxStoreRequestFunc func(r *http.Request, gqlRequest *graphql.Request)
ctxRetrieveRequestFunc func(r *http.Request) *graphql.Request
newReusableBodyReadCloser NewReusableBodyReadCloserFunc
seekReadCloser SeekReadCloserFunc
tykVariableReplacer TykVariableReplacer
}
EngineV2Injections
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| BeforeFetchHook |
|
No comment on field. |
| AfterFetchHook |
|
No comment on field. |
| WebsocketOnBeforeStart |
|
No comment on field. |
| ContextStoreRequest |
|
No comment on field. |
| ContextRetrieveRequest |
|
No comment on field. |
| NewReusableBodyReadCloser |
|
No comment on field. |
| SeekReadCloser |
|
No comment on field. |
| TykVariableReplacer |
|
No comment on field. |
type EngineV2Injections struct {
BeforeFetchHook resolve.BeforeFetchHook
AfterFetchHook resolve.AfterFetchHook
WebsocketOnBeforeStart graphql.WebsocketBeforeStartHook
ContextStoreRequest ContextStoreRequestV1Func
ContextRetrieveRequest ContextRetrieveRequestV1Func
NewReusableBodyReadCloser NewReusableBodyReadCloserFunc
SeekReadCloser SeekReadCloserFunc
TykVariableReplacer TykVariableReplacer
}
EngineV2OTelConfig
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| Enabled |
|
No comment on field. |
| Config |
|
No comment on field. |
| TracerProvider |
|
No comment on field. |
| Executor |
|
No comment on field. |
type EngineV2OTelConfig struct {
Enabled bool
Config otel.OpenTelemetry
TracerProvider otel.TracerProvider
Executor graphqlinternal.TykOtelExecutorI
}
EngineV2Options
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| Logger |
|
No comment on field. |
| Schema |
|
No comment on field. |
| ApiDefinition |
|
No comment on field. |
| HttpClient |
|
No comment on field. |
| StreamingClient |
|
No comment on field. |
| OpenTelemetry |
|
No comment on field. |
| Injections |
|
No comment on field. |
type EngineV2Options struct {
Logger *logrus.Logger
Schema *graphql.Schema
ApiDefinition *apidef.APIDefinition
HttpClient *http.Client
StreamingClient *http.Client
OpenTelemetry EngineV2OTelConfig
Injections EngineV2Injections
}
EngineV3
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| engine |
|
No comment on field. |
| schema |
|
No comment on field. |
| logger |
|
No comment on field. |
| openTelemetry |
|
No comment on field. |
| apiDefinition |
|
No comment on field. |
| ctxStoreRequestFunc |
|
No comment on field. |
| ctxRetrieveRequestFunc |
|
No comment on field. |
| gqlTools |
|
No comment on field. |
| graphqlRequestProcessor |
|
No comment on field. |
| complexityChecker |
|
No comment on field. |
| granularAccessChecker |
|
No comment on field. |
| reverseProxyPreHandler |
|
No comment on field. |
| contextCancel |
|
No comment on field. |
| newReusableBodyReadCloser |
|
No comment on field. |
| seekReadCloser |
|
No comment on field. |
| tykVariableReplacer |
|
No comment on field. |
type EngineV3 struct {
engine *graphqlv2.ExecutionEngineV2
schema *graphqlv2.Schema
logger abstractlogger.Logger
openTelemetry *EngineV2OTelConfig
apiDefinition *apidef.APIDefinition
ctxStoreRequestFunc ContextStoreRequestV2Func
ctxRetrieveRequestFunc ContextRetrieveRequestV2Func
gqlTools graphqlGoToolsV2
graphqlRequestProcessor GraphQLRequestProcessor
complexityChecker ComplexityChecker
granularAccessChecker GranularAccessChecker
reverseProxyPreHandler ReverseProxyPreHandler
contextCancel context.CancelFunc
newReusableBodyReadCloser NewReusableBodyReadCloserFunc
seekReadCloser SeekReadCloserFunc
tykVariableReplacer TykVariableReplacer
}
EngineV3Injections
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| WebsocketOnBeforeStart |
|
No comment on field. |
| ContextStoreRequest |
|
No comment on field. |
| ContextRetrieveRequest |
|
No comment on field. |
| NewReusableBodyReadCloser |
|
No comment on field. |
| SeekReadCloser |
|
No comment on field. |
| TykVariableReplacer |
|
No comment on field. |
type EngineV3Injections struct {
WebsocketOnBeforeStart graphqlv2.WebsocketBeforeStartHook
ContextStoreRequest ContextStoreRequestV2Func
ContextRetrieveRequest ContextRetrieveRequestV2Func
NewReusableBodyReadCloser NewReusableBodyReadCloserFunc
SeekReadCloser SeekReadCloserFunc
TykVariableReplacer TykVariableReplacer
}
EngineV3Options
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| Logger |
|
No comment on field. |
| Schema |
|
No comment on field. |
| ApiDefinition |
|
No comment on field. |
| HttpClient |
|
No comment on field. |
| StreamingClient |
|
No comment on field. |
| OpenTelemetry |
|
No comment on field. |
| Injections |
|
No comment on field. |
type EngineV3Options struct {
Logger *logrus.Logger
Schema *graphqlv2.Schema
ApiDefinition *apidef.APIDefinition
HttpClient *http.Client
StreamingClient *http.Client
OpenTelemetry EngineV2OTelConfig
Injections EngineV3Injections
}
EngineVersion
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type EngineVersion int
GranularAccessChecker
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type GranularAccessChecker interface {
CheckGraphQLRequestFieldAllowance(w http.ResponseWriter, r *http.Request, accessDefinition *GranularAccessDefinition) GraphQLGranularAccessResult
}
GranularAccessDefinition
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| AllowedTypes |
|
No comment on field. |
| RestrictedTypes |
|
No comment on field. |
| DisableIntrospection |
|
No comment on field. |
type GranularAccessDefinition struct {
AllowedTypes []GranularAccessType
RestrictedTypes []GranularAccessType
DisableIntrospection bool
}
GranularAccessFailReason
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type GranularAccessFailReason int
GranularAccessType
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| Name |
|
No comment on field. |
| Fields |
|
No comment on field. |
type GranularAccessType struct {
Name string
Fields []string
}
GraphQLEngineTransport
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| originalTransport |
|
No comment on field. |
| transportType |
|
No comment on field. |
| newReusableBodyReadCloser |
|
No comment on field. |
| headersConfig |
|
No comment on field. |
type GraphQLEngineTransport struct {
originalTransport http.RoundTripper
transportType GraphQLEngineTransportType
newReusableBodyReadCloser NewReusableBodyReadCloserFunc
headersConfig ReverseProxyHeadersConfig
}
GraphQLEngineTransportType
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type GraphQLEngineTransportType int
GraphQLGranularAccessResult
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| FailReason |
|
No comment on field. |
| ValidationError |
|
No comment on field. |
| InternalErr |
|
No comment on field. |
| writeErrorResponse |
|
No comment on field. |
type GraphQLGranularAccessResult struct {
FailReason GranularAccessFailReason
ValidationError error
InternalErr error
writeErrorResponse func(w io.Writer, providedErr error) (n int, err error)
}
GraphQLProxyOnlyContext
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
|
No comment on field. | |
| forwardedRequest |
|
No comment on field. |
| upstreamResponse |
|
No comment on field. |
| ignoreForwardedHeaders |
|
No comment on field. |
type GraphQLProxyOnlyContext struct {
context.Context
forwardedRequest *http.Request
upstreamResponse *http.Response
ignoreForwardedHeaders map[string]bool
}
GraphQLProxyOnlyContextValues
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| forwardedRequest |
|
No comment on field. |
| upstreamResponse |
|
No comment on field. |
| ignoreForwardedHeaders |
|
No comment on field. |
type GraphQLProxyOnlyContextValues struct {
forwardedRequest *http.Request
upstreamResponse *http.Response
ignoreForwardedHeaders map[string]bool
}
GraphQLRequestProcessor
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type GraphQLRequestProcessor interface {
ProcessRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) (error, int)
}
NewReusableBodyReadCloserFunc
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type NewReusableBodyReadCloserFunc func(io.ReadCloser) (io.ReadCloser, error)
ProcessGraphQLComplexityParams
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| w |
|
No comment on field. |
| r |
|
No comment on field. |
type ProcessGraphQLComplexityParams struct {
w http.ResponseWriter
r *http.Request
}
ProxyOnlyHeadersConfig
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| UseImmutableHeaders |
|
No comment on field. |
| RequestHeadersRewrite |
|
No comment on field. |
type ProxyOnlyHeadersConfig struct {
UseImmutableHeaders bool
RequestHeadersRewrite map[string]apidef.RequestHeadersRewriteConfig
}
ReverseProxyHeadersConfig
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| ProxyOnly |
|
No comment on field. |
type ReverseProxyHeadersConfig struct {
ProxyOnly ProxyOnlyHeadersConfig
}
ReverseProxyParams
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| RoundTripper |
|
No comment on field. |
| ResponseWriter |
|
No comment on field. |
| OutRequest |
|
No comment on field. |
| WebSocketUpgrader |
|
No comment on field. |
| NeedsEngine |
|
No comment on field. |
| IsCORSPreflight |
|
No comment on field. |
| IsWebSocketUpgrade |
|
No comment on field. |
| HeadersConfig |
|
No comment on field. |
type ReverseProxyParams struct {
RoundTripper http.RoundTripper
ResponseWriter http.ResponseWriter
OutRequest *http.Request
WebSocketUpgrader *websocket.Upgrader
NeedsEngine bool
IsCORSPreflight bool
IsWebSocketUpgrade bool
HeadersConfig ReverseProxyHeadersConfig
}
ReverseProxyPreHandler
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type ReverseProxyPreHandler interface {
PreHandle(params ReverseProxyParams) (reverseProxyType ReverseProxyType, err error)
}
ReverseProxyType
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type ReverseProxyType int
SeekReadCloserFunc
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type SeekReadCloserFunc func(io.ReadCloser) (io.ReadCloser, error)
TransportModifier
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type TransportModifier func(roundTripper http.RoundTripper, apiDefinition *apidef.APIDefinition) http.RoundTripper
TykVariableReplacer
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type TykVariableReplacer func(r *http.Request, in string, escape bool) string
complexityCheckerV1
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| logger |
|
No comment on field. |
| schema |
|
No comment on field. |
| ctxRetrieveRequest |
|
No comment on field. |
type complexityCheckerV1 struct {
logger abstractlogger.Logger
schema *graphql.Schema
ctxRetrieveRequest ContextRetrieveRequestV1Func
}
complexityCheckerV2
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| schema |
|
No comment on field. |
| logger |
|
No comment on field. |
| ctxRetrieveRequest |
|
No comment on field. |
type complexityCheckerV2 struct {
schema *graphqlv2.Schema
logger abstractlogger.Logger
ctxRetrieveRequest ContextRetrieveRequestV2Func
}
contextKey
This type doesn't have documentation.
type contextKey struct{}
createExecutionEngineV1Params
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| logger |
|
No comment on field. |
| apiDef |
|
No comment on field. |
| schema |
|
No comment on field. |
| httpClient |
|
No comment on field. |
| preSendHttpHook |
|
No comment on field. |
| postReceiveHttpHook |
|
No comment on field. |
type createExecutionEngineV1Params struct {
logger abstractlogger.Logger
apiDef *apidef.APIDefinition
schema *graphql.Schema
httpClient *http.Client
preSendHttpHook datasource.PreSendHttpHook
postReceiveHttpHook datasource.PostReceiveHttpHook
}
granularAccessCheckerV1
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| logger |
|
No comment on field. |
| schema |
|
No comment on field. |
| ctxRetrieveGraphQLRequest |
|
No comment on field. |
type granularAccessCheckerV1 struct {
logger abstractlogger.Logger
schema *graphql.Schema
ctxRetrieveGraphQLRequest ContextRetrieveRequestV1Func
}
granularAccessCheckerV2
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| logger |
|
No comment on field. |
| schema |
|
No comment on field. |
| ctxRetrieveGraphQLRequest |
|
No comment on field. |
type granularAccessCheckerV2 struct {
logger abstractlogger.Logger
schema *graphqlv2.Schema
ctxRetrieveGraphQLRequest ContextRetrieveRequestV2Func
}
graphqlGoToolsV1
graphqlGoToolsV1 is a stateless utility struct that abstracts graphql-go-tools/v1 functionality. Also useful for namespacing.
type graphqlGoToolsV1 struct{}
graphqlGoToolsV2
This type doesn't have documentation.
type graphqlGoToolsV2 struct{}
graphqlRequestProcessorV1
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| logger |
|
No comment on field. |
| schema |
|
No comment on field. |
| ctxRetrieveRequest |
|
No comment on field. |
type graphqlRequestProcessorV1 struct {
logger abstractlogger.Logger
schema *graphql.Schema
ctxRetrieveRequest ContextRetrieveRequestV1Func
}
graphqlRequestProcessorWithOTelV1
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| logger |
|
No comment on field. |
| schema |
|
No comment on field. |
| otelExecutor |
|
No comment on field. |
| ctxRetrieveRequest |
|
No comment on field. |
type graphqlRequestProcessorWithOTelV1 struct {
logger abstractlogger.Logger
schema *graphql.Schema
otelExecutor internalgraphql.TykOtelExecutorI
ctxRetrieveRequest ContextRetrieveRequestV1Func
}
reverseProxyPreHandlerV1
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| ctxRetrieveGraphQLRequest |
|
No comment on field. |
| apiDefinition |
|
No comment on field. |
| httpClient |
|
No comment on field. |
| newReusableBodyReadCloser |
|
No comment on field. |
type reverseProxyPreHandlerV1 struct {
ctxRetrieveGraphQLRequest ContextRetrieveRequestV1Func
apiDefinition *apidef.APIDefinition
httpClient *http.Client
newReusableBodyReadCloser NewReusableBodyReadCloserFunc
}
reverseProxyPreHandlerV2
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| ctxRetrieveGraphQLRequest |
|
No comment on field. |
| apiDefinition |
|
No comment on field. |
| httpClient |
|
No comment on field. |
| newReusableBodyReadCloser |
|
No comment on field. |
type reverseProxyPreHandlerV2 struct {
ctxRetrieveGraphQLRequest ContextRetrieveRequestV2Func
apiDefinition *apidef.APIDefinition
httpClient *http.Client
newReusableBodyReadCloser NewReusableBodyReadCloserFunc
}
Functions
func DetermineGraphQLEngineTransportType
func DetermineGraphQLEngineTransportType(apiDefinition *apidef.APIDefinition) GraphQLEngineTransportType {
switch apiDefinition.GraphQL.ExecutionMode {
case apidef.GraphQLExecutionModeSubgraph:
fallthrough
case apidef.GraphQLExecutionModeProxyOnly:
return GraphQLEngineTransportTypeProxyOnly
}
return GraphQLEngineTransportTypeMultiUpstream
}
Cognitive complexity: 4, Cyclomatic complexity: 4
func GetProxyOnlyContextValue
func GetProxyOnlyContextValue(ctx context.Context) *GraphQLProxyOnlyContextValues {
val, ok := ctx.Value(graphqlProxyContextInfo).(*GraphQLProxyOnlyContextValues)
if !ok {
return nil
}
return val
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func GetSchemaV1
func GetSchemaV1(engine Engine) (*graphql.Schema, error) {
switch engine.Version() {
case EngineVersionV1:
return engine.(*EngineV1).Schema, nil
case EngineVersionV2:
return engine.(*EngineV2).Schema, nil
}
return nil, errors.New("schema not supported for engine type")
}
Cognitive complexity: 4, Cyclomatic complexity: 4
func GetSchemaV2
func GetSchemaV2(engine Engine) (*graphqlv2.Schema, error) {
switch engine.Version() {
case EngineVersionV3:
// Handle for tyk graph engine v3
}
return nil, errors.New("schema not supported for engine type")
}
Cognitive complexity: 3, Cyclomatic complexity: 3
func NewEngineV1
func NewEngineV1(options EngineV1Options) (*EngineV1, error) {
logger := createAbstractLogrusLogger(options.Logger)
gqlTools := graphqlGoToolsV1{}
var parsedSchema = options.Schema
if parsedSchema == nil {
var err error
parsedSchema, err = gqlTools.parseSchema(options.ApiDefinition.GraphQL.Schema)
if err != nil {
logger.Error("error on schema parsing", abstractlogger.Error(err))
return nil, err
}
}
executionEngine, err := gqlTools.createExecutionEngine(createExecutionEngineV1Params{
logger: logger,
apiDef: options.ApiDefinition,
schema: parsedSchema,
httpClient: options.HttpClient,
preSendHttpHook: options.Injections.PreSendHttpHook,
postReceiveHttpHook: options.Injections.PostReceiveHttpHook,
})
if err != nil {
logger.Error("error on execution engine creation", abstractlogger.Error(err))
return nil, err
}
requestProcessor := &graphqlRequestProcessorV1{
logger: logger,
schema: parsedSchema,
ctxRetrieveRequest: options.Injections.ContextRetrieveRequest,
}
complexityChecker := &complexityCheckerV1{
logger: logger,
schema: parsedSchema,
ctxRetrieveRequest: options.Injections.ContextRetrieveRequest,
}
granularAccessChecker := &granularAccessCheckerV1{
logger: logger,
schema: parsedSchema,
ctxRetrieveGraphQLRequest: options.Injections.ContextRetrieveRequest,
}
reverseProxyPreHandler := &reverseProxyPreHandlerV1{
ctxRetrieveGraphQLRequest: options.Injections.ContextRetrieveRequest,
apiDefinition: options.ApiDefinition,
httpClient: options.HttpClient,
newReusableBodyReadCloser: options.Injections.NewReusableBodyReadCloser,
}
return &EngineV1{
ExecutionEngine: executionEngine,
Schema: parsedSchema,
ApiDefinition: options.ApiDefinition,
HttpClient: options.HttpClient,
logger: logger,
gqlTools: gqlTools,
graphqlRequestProcessor: requestProcessor,
complexityChecker: complexityChecker,
granularAccessChecker: granularAccessChecker,
reverseProxyPreHandler: reverseProxyPreHandler,
ctxStoreRequestFunc: options.Injections.ContextStoreRequest,
ctxRetrieveRequestFunc: options.Injections.ContextRetrieveRequest,
}, nil
}
Cognitive complexity: 13, Cyclomatic complexity: 4
func NewEngineV2
func NewEngineV2(options EngineV2Options) (*EngineV2, error) {
logger := createAbstractLogrusLogger(options.Logger)
gqlTools := graphqlGoToolsV1{}
var parsedSchema = options.Schema
if parsedSchema == nil {
var err error
parsedSchema, err = gqlTools.parseSchema(options.ApiDefinition.GraphQL.Schema)
if err != nil {
logger.Error("error on schema parsing", abstractlogger.Error(err))
return nil, err
}
}
configAdapter := adapter.NewGraphQLConfigAdapter(options.ApiDefinition,
adapter.WithHttpClient(options.HttpClient),
adapter.WithStreamingClient(options.StreamingClient),
adapter.WithSchema(parsedSchema),
)
engineConfig, err := configAdapter.EngineConfigV2()
if err != nil {
options.Logger.WithError(err).Error("could not create engine v2 config")
return nil, err
}
engineConfig.SetWebsocketBeforeStartHook(options.Injections.WebsocketOnBeforeStart)
specCtx, cancel := context.WithCancel(context.Background())
executionEngine, err := graphql.NewExecutionEngineV2(specCtx, logger, *engineConfig)
if err != nil {
options.Logger.WithError(err).Error("could not create execution engine v2")
cancel()
return nil, err
}
requestProcessor := &graphqlRequestProcessorV1{
logger: logger,
schema: parsedSchema,
ctxRetrieveRequest: options.Injections.ContextRetrieveRequest,
}
complexityChecker := &complexityCheckerV1{
logger: logger,
schema: parsedSchema,
ctxRetrieveRequest: options.Injections.ContextRetrieveRequest,
}
granularAccessChecker := &granularAccessCheckerV1{
logger: logger,
schema: parsedSchema,
ctxRetrieveGraphQLRequest: options.Injections.ContextRetrieveRequest,
}
reverseProxyPreHandler := &reverseProxyPreHandlerV1{
ctxRetrieveGraphQLRequest: options.Injections.ContextRetrieveRequest,
apiDefinition: options.ApiDefinition,
httpClient: options.HttpClient,
newReusableBodyReadCloser: options.Injections.NewReusableBodyReadCloser,
}
engineV2 := &EngineV2{
ExecutionEngine: executionEngine,
Schema: parsedSchema,
ApiDefinition: options.ApiDefinition,
HttpClient: options.HttpClient,
StreamingClient: options.StreamingClient,
OpenTelemetry: &options.OpenTelemetry,
logger: logger,
gqlTools: gqlTools,
graphqlRequestProcessor: requestProcessor,
complexityChecker: complexityChecker,
granularAccessChecker: granularAccessChecker,
reverseProxyPreHandler: reverseProxyPreHandler,
contextCancel: cancel,
beforeFetchHook: options.Injections.BeforeFetchHook,
afterFetchHook: options.Injections.AfterFetchHook,
ctxStoreRequestFunc: options.Injections.ContextStoreRequest,
ctxRetrieveRequestFunc: options.Injections.ContextRetrieveRequest,
newReusableBodyReadCloser: options.Injections.NewReusableBodyReadCloser,
seekReadCloser: options.Injections.SeekReadCloser,
tykVariableReplacer: options.Injections.TykVariableReplacer,
}
if engineV2.OpenTelemetry == nil {
engineV2.OpenTelemetry = &EngineV2OTelConfig{}
}
if engineV2.OpenTelemetry.Enabled {
var executor graphqlinternal.TykOtelExecutorI
if options.ApiDefinition.DetailedTracing {
executor, err = graphqlinternal.NewOtelGraphqlEngineV2Detailed(engineV2.OpenTelemetry.TracerProvider, executionEngine, parsedSchema)
} else {
executor, err = graphqlinternal.NewOtelGraphqlEngineV2Basic(engineV2.OpenTelemetry.TracerProvider, executionEngine)
}
if err != nil {
options.Logger.WithError(err).Error("error creating custom execution engine v2")
cancel()
return nil, err
}
otelRequestProcessor := &graphqlRequestProcessorWithOTelV1{
logger: logger,
schema: parsedSchema,
otelExecutor: executor,
ctxRetrieveRequest: options.Injections.ContextRetrieveRequest,
}
engineV2.graphqlRequestProcessor = otelRequestProcessor
engineV2.OpenTelemetry.Executor = executor
}
if isSupergraph(options.ApiDefinition) {
engineV2.ApiDefinition.GraphQL.Schema = engineV2.ApiDefinition.GraphQL.Supergraph.MergedSDL
}
return engineV2, nil
}
Cognitive complexity: 28, Cyclomatic complexity: 10
func NewEngineV3
func NewEngineV3(options EngineV3Options) (*EngineV3, error) {
logger := createAbstractLogrusLogger(options.Logger)
gqlTools := graphqlGoToolsV2{}
var parsedSchema = options.Schema
if parsedSchema == nil {
var err error
parsedSchema, err = gqlTools.parseSchema(options.ApiDefinition.GraphQL.Schema)
if err != nil {
logger.Error("error on schema parsing", abstractlogger.Error(err))
return nil, err
}
}
// TODO check the streaming client usage here
configAdapter := adapter.NewGraphQLConfigAdapter(options.ApiDefinition,
adapter.WithHttpClient(options.HttpClient),
adapter.WithV2Schema(options.Schema),
adapter.WithStreamingClient(options.StreamingClient),
)
engineConfig, err := configAdapter.EngineConfigV3()
if err != nil {
options.Logger.WithError(err).Error("could not create engine v2 config")
return nil, err
}
engineConfig.SetWebsocketBeforeStartHook(options.Injections.WebsocketOnBeforeStart)
specCtx, cancel := context.WithCancel(context.Background())
executionEngine, err := graphqlv2.NewExecutionEngineV2(specCtx, logger, *engineConfig)
if err != nil {
options.Logger.WithError(err).Error("could not create execution engine v2")
cancel()
return nil, err
}
//
//requestProcessor := &graphqlRequestProcessorV1{
// logger: logger,
// schema: parsedSchema,
// ctxRetrieveRequest: options.Injections.ContextRetrieveRequest,
//}
//
complexityChecker := &complexityCheckerV2{
logger: logger,
schema: parsedSchema,
ctxRetrieveRequest: options.Injections.ContextRetrieveRequest,
}
granularAccessChecker := &granularAccessCheckerV2{
logger: logger,
schema: parsedSchema,
ctxRetrieveGraphQLRequest: options.Injections.ContextRetrieveRequest,
}
reverseProxyPreHandler := &reverseProxyPreHandlerV2{
ctxRetrieveGraphQLRequest: options.Injections.ContextRetrieveRequest,
apiDefinition: options.ApiDefinition,
httpClient: options.HttpClient,
newReusableBodyReadCloser: options.Injections.NewReusableBodyReadCloser,
}
engine := EngineV3{
logger: logger,
schema: options.Schema,
engine: executionEngine,
ctxRetrieveRequestFunc: options.Injections.ContextRetrieveRequest,
ctxStoreRequestFunc: options.Injections.ContextStoreRequest,
openTelemetry: &options.OpenTelemetry,
apiDefinition: options.ApiDefinition,
reverseProxyPreHandler: reverseProxyPreHandler,
gqlTools: gqlTools,
tykVariableReplacer: options.Injections.TykVariableReplacer,
seekReadCloser: options.Injections.SeekReadCloser,
contextCancel: cancel,
complexityChecker: complexityChecker,
granularAccessChecker: granularAccessChecker,
}
if engine.openTelemetry == nil {
engine.openTelemetry = &EngineV2OTelConfig{}
}
if engine.openTelemetry.Enabled {
var executor graphqlinternal.TykOtelExecutorI
if options.ApiDefinition.DetailedTracing {
//executor, err = graphqlinternal.NewOtelGraphqlEngineV2Detailed(engine.openTelemetry.TracerProvider, executionEngine, parsedSchema)
} else {
//executor, err = graphqlinternal.NewOtelGraphqlEngineV2Basic(engine.openTelemetry.TracerProvider, executionEngine)
}
if err != nil {
options.Logger.WithError(err).Error("error creating custom execution engine v2")
cancel()
return nil, err
}
otelRequestProcessor := &graphqlRequestProcessorWithOTelV1{
logger: logger,
//schema: parsedSchema,
otelExecutor: executor,
//ctxRetrieveRequest: options.Injections.ContextRetrieveRequest,
}
engine.graphqlRequestProcessor = otelRequestProcessor
engine.openTelemetry.Executor = executor
}
if isSupergraph(options.ApiDefinition) {
engine.apiDefinition.GraphQL.Schema = engine.apiDefinition.GraphQL.Supergraph.MergedSDL
}
return &engine, nil
}
Cognitive complexity: 27, Cyclomatic complexity: 10
func NewGraphQLEngineTransport
func NewGraphQLEngineTransport(
transportType GraphQLEngineTransportType,
originalTransport http.RoundTripper,
newReusableBodyReadCloser NewReusableBodyReadCloserFunc,
headersConfig ReverseProxyHeadersConfig,
) *GraphQLEngineTransport {
transport := &GraphQLEngineTransport{
originalTransport: originalTransport,
transportType: transportType,
newReusableBodyReadCloser: newReusableBodyReadCloser,
headersConfig: headersConfig,
}
return transport
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func NewGraphQLProxyOnlyContext
func NewGraphQLProxyOnlyContext(ctx context.Context, forwardedRequest *http.Request) *GraphQLProxyOnlyContext {
return &GraphQLProxyOnlyContext{
Context: ctx,
forwardedRequest: forwardedRequest,
ignoreForwardedHeaders: map[string]bool{
http.CanonicalHeaderKey("date"): true,
http.CanonicalHeaderKey("content-type"): true,
http.CanonicalHeaderKey("content-length"): true,
},
}
}
Cognitive complexity: 2, Cyclomatic complexity: 1
func SetProxyOnlyContextValue
func SetProxyOnlyContextValue(ctx context.Context, req *http.Request) context.Context {
value := &GraphQLProxyOnlyContextValues{
forwardedRequest: req,
ignoreForwardedHeaders: map[string]bool{
http.CanonicalHeaderKey("date"): true,
http.CanonicalHeaderKey("content-type"): true,
http.CanonicalHeaderKey("content-length"): true,
},
}
return context.WithValue(ctx, graphqlProxyContextInfo, value)
}
Cognitive complexity: 2, Cyclomatic complexity: 1
func (*EngineV1) Cancel
func (e *EngineV1) Cancel() {
// V1 does not have a cancel callback
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV1) HandleReverseProxy
func (e *EngineV1) HandleReverseProxy(params ReverseProxyParams) (res *http.Response, hijacked bool, err error) {
reverseProxyType, err := e.reverseProxyPreHandler.PreHandle(params)
if err != nil {
e.logger.Error("error on reverse proxy pre handler", abstractlogger.Error(err))
return nil, false, err
}
gqlRequest := e.ctxRetrieveRequestFunc(params.OutRequest)
switch reverseProxyType {
case ReverseProxyTypeIntrospection:
return e.gqlTools.handleIntrospection(e.Schema)
case ReverseProxyTypeWebsocketUpgrade:
return e.handoverWebSocketConnectionToGraphQLExecutionEngine(¶ms)
case ReverseProxyTypeGraphEngine:
return e.handoverRequestToGraphQLExecutionEngine(gqlRequest, params.OutRequest)
case ReverseProxyTypePreFlight:
if e.ApiDefinition.GraphQL.ExecutionMode == apidef.GraphQLExecutionModeProxyOnly {
return nil, false, nil
}
return nil, false, errors.New("options passthrough not allowed")
case ReverseProxyTypeNone:
return nil, false, nil
}
e.logger.Error("unknown reverse proxy type", abstractlogger.Int("reverseProxyType", int(reverseProxyType)))
return nil, false, ErrUnknownReverseProxyType
}
Cognitive complexity: 11, Cyclomatic complexity: 9
func (*EngineV1) HasSchema
func (e *EngineV1) HasSchema() bool {
return e.Schema != nil
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV1) ProcessAndStoreGraphQLRequest
func (e *EngineV1) ProcessAndStoreGraphQLRequest(w http.ResponseWriter, r *http.Request) (err error, statusCode int) {
var gqlRequest graphql.Request
err = graphql.UnmarshalRequest(r.Body, &gqlRequest)
if err != nil {
e.logger.Debug("error while unmarshalling GraphQL request", abstractlogger.Error(err))
return err, http.StatusBadRequest
}
e.ctxStoreRequestFunc(r, &gqlRequest)
return e.graphqlRequestProcessor.ProcessRequest(r.Context(), w, r)
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*EngineV1) ProcessGraphQLComplexity
func (e *EngineV1) ProcessGraphQLComplexity(r *http.Request, accessDefinition *ComplexityAccessDefinition) (err error, statusCode int) {
return complexityFailReasonAsHttpStatusCode(e.complexityChecker.DepthLimitExceeded(r, accessDefinition))
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV1) ProcessGraphQLGranularAccess
func (e *EngineV1) ProcessGraphQLGranularAccess(w http.ResponseWriter, r *http.Request, accessDefinition *GranularAccessDefinition) (err error, statusCode int) {
result := e.granularAccessChecker.CheckGraphQLRequestFieldAllowance(w, r, accessDefinition)
return granularAccessFailReasonAsHttpStatusCode(e.logger, &result, w)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV1) Version
func (e *EngineV1) Version() EngineVersion {
return EngineVersionV1
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV2) Cancel
func (e *EngineV2) Cancel() {
if e.contextCancel != nil {
e.contextCancel()
}
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*EngineV2) HandleReverseProxy
func (e *EngineV2) HandleReverseProxy(params ReverseProxyParams) (res *http.Response, hijacked bool, err error) {
reverseProxyType, err := e.reverseProxyPreHandler.PreHandle(params)
if err != nil {
e.logger.Error("error on reverse proxy pre handler", abstractlogger.Error(err))
return nil, false, err
}
switch reverseProxyType {
case ReverseProxyTypeIntrospection:
return e.gqlTools.handleIntrospection(e.Schema)
case ReverseProxyTypeWebsocketUpgrade:
return e.handoverWebSocketConnectionToGraphQLExecutionEngine(¶ms)
case ReverseProxyTypeGraphEngine:
gqlRequest := e.ctxRetrieveRequestFunc(params.OutRequest)
// Cleanup method frees allocated resources if they are eligible for freeing up.
// Currently, it only frees up the allocated resources of a GraphQL query that
// has a cached query plan.
//
// graphql-go-tools uses the parsed query (ast.Document in graphql-go-tools codebase)
// in the planner and caches the plans. If a plan has been cached, we can reset the created
// ast.Document struct and put it back in the pool for later use. In this way, we can reduce the GC
// pressure and number of allocations per GraphQL query.
// See TT-9864 for the details.
defer gqlRequest.Cleanup()
return e.handoverRequestToGraphQLExecutionEngine(gqlRequest, params.OutRequest)
case ReverseProxyTypePreFlight:
if e.ApiDefinition.GraphQL.ExecutionMode == apidef.GraphQLExecutionModeProxyOnly {
return nil, false, nil
}
return nil, false, errors.New("options passthrough not allowed")
case ReverseProxyTypeNone:
return nil, false, nil
}
e.logger.Error("unknown reverse proxy type", abstractlogger.Int("reverseProxyType", int(reverseProxyType)))
return nil, false, ErrUnknownReverseProxyType
}
Cognitive complexity: 11, Cyclomatic complexity: 9
func (*EngineV2) HasSchema
func (e *EngineV2) HasSchema() bool {
return e.Schema != nil
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV2) ProcessAndStoreGraphQLRequest
func (e *EngineV2) ProcessAndStoreGraphQLRequest(w http.ResponseWriter, r *http.Request) (err error, statusCode int) {
var gqlRequest graphql.Request
err = graphql.UnmarshalRequest(r.Body, &gqlRequest)
if err != nil {
e.logger.Debug("error while unmarshalling GraphQL request", abstractlogger.Error(err))
return err, http.StatusBadRequest
}
e.ctxStoreRequestFunc(r, &gqlRequest)
if e.OpenTelemetry.Enabled && e.ApiDefinition.DetailedTracing {
ctx, span := e.OpenTelemetry.TracerProvider.Tracer().Start(r.Context(), "GraphqlMiddleware Validation")
defer span.End()
*r = *r.WithContext(ctx)
}
return e.graphqlRequestProcessor.ProcessRequest(r.Context(), w, r)
}
Cognitive complexity: 4, Cyclomatic complexity: 4
func (*EngineV2) ProcessGraphQLComplexity
func (e *EngineV2) ProcessGraphQLComplexity(r *http.Request, accessDefinition *ComplexityAccessDefinition) (err error, statusCode int) {
return complexityFailReasonAsHttpStatusCode(e.complexityChecker.DepthLimitExceeded(r, accessDefinition))
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV2) ProcessGraphQLGranularAccess
func (e *EngineV2) ProcessGraphQLGranularAccess(w http.ResponseWriter, r *http.Request, accessDefinition *GranularAccessDefinition) (err error, statusCode int) {
result := e.granularAccessChecker.CheckGraphQLRequestFieldAllowance(w, r, accessDefinition)
return granularAccessFailReasonAsHttpStatusCode(e.logger, &result, w)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV2) Version
func (e *EngineV2) Version() EngineVersion {
return EngineVersionV2
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV3) Cancel
func (e *EngineV3) Cancel() {
if e.contextCancel != nil {
e.contextCancel()
}
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*EngineV3) HandleReverseProxy
func (e *EngineV3) HandleReverseProxy(params ReverseProxyParams) (res *http.Response, hijacked bool, err error) {
reverseProxyType, err := e.reverseProxyPreHandler.PreHandle(params)
if err != nil {
e.logger.Error("error on reverse proxy pre handler", abstractlogger.Error(err))
return nil, false, err
}
gqlRequest := e.ctxRetrieveRequestFunc(params.OutRequest)
switch reverseProxyType {
case ReverseProxyTypeIntrospection:
return e.gqlTools.handleIntrospection(e.schema)
case ReverseProxyTypeWebsocketUpgrade:
return e.handoverWebSocketConnectionToGraphQLExecutionEngine(¶ms)
case ReverseProxyTypeGraphEngine:
return e.handoverRequestToGraphQLExecutionEngine(gqlRequest, params.OutRequest)
case ReverseProxyTypePreFlight:
if e.apiDefinition.GraphQL.ExecutionMode == apidef.GraphQLExecutionModeProxyOnly {
return nil, false, nil
}
return nil, false, errors.New("options passthrough not allowed")
case ReverseProxyTypeNone:
return nil, false, nil
}
e.logger.Error("unknown reverse proxy type", abstractlogger.Int("reverseProxyType", int(reverseProxyType)))
return nil, false, ErrUnknownReverseProxyType
}
Cognitive complexity: 11, Cyclomatic complexity: 9
func (*EngineV3) HasSchema
func (e *EngineV3) HasSchema() bool {
return e.schema != nil
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV3) ProcessAndStoreGraphQLRequest
func (e *EngineV3) ProcessAndStoreGraphQLRequest(w http.ResponseWriter, r *http.Request) (err error, statusCode int) {
var gqlRequest graphqlv2.Request
err = graphqlv2.UnmarshalRequest(r.Body, &gqlRequest)
if err != nil {
e.logger.Debug("error while unmarshalling GraphQL request", abstractlogger.Error(err))
return err, http.StatusBadRequest
}
e.ctxStoreRequestFunc(r, &gqlRequest)
if e.openTelemetry.Enabled && e.apiDefinition.DetailedTracing {
ctx, span := e.openTelemetry.TracerProvider.Tracer().Start(r.Context(), "GraphqlMiddleware Validation")
defer span.End()
*r = *r.WithContext(ctx)
}
return e.ProcessRequest(r.Context(), w, r)
}
Cognitive complexity: 4, Cyclomatic complexity: 4
func (*EngineV3) ProcessGraphQLComplexity
func (e *EngineV3) ProcessGraphQLComplexity(r *http.Request, accessDefinition *ComplexityAccessDefinition) (err error, statusCode int) {
return complexityFailReasonAsHttpStatusCode(e.complexityChecker.DepthLimitExceeded(r, accessDefinition))
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV3) ProcessGraphQLGranularAccess
func (e *EngineV3) ProcessGraphQLGranularAccess(w http.ResponseWriter, r *http.Request, accessDefinition *GranularAccessDefinition) (err error, statusCode int) {
result := e.granularAccessChecker.CheckGraphQLRequestFieldAllowance(w, r, accessDefinition)
return granularAccessFailReasonAsHttpStatusCode(e.logger, &result, w)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*EngineV3) ProcessRequest
func (e *EngineV3) ProcessRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) (error, int) {
if r == nil {
e.logger.Error("request is nil")
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
gqlRequest := e.ctxRetrieveRequestFunc(r)
normalizationResult, err := gqlRequest.Normalize(e.schema)
if err != nil {
e.logger.Error("error while normalizing GraphQL request", abstractlogger.Error(err))
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
if normalizationResult.Errors != nil && normalizationResult.Errors.Count() > 0 {
return writeGraphQLError(e.logger, w, normalizationResult.Errors)
}
validationResult, err := gqlRequest.ValidateForSchema(e.schema)
if err != nil {
e.logger.Error("error while validating GraphQL request", abstractlogger.Error(err))
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
if validationResult.Errors != nil && validationResult.Errors.Count() > 0 {
return writeGraphQLError(e.logger, w, validationResult.Errors)
}
inputValidationResult, err := gqlRequest.ValidateInput(e.schema)
if err != nil {
e.logger.Error("error while validating variables for request", abstractlogger.Error(err))
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
if inputValidationResult.Errors != nil && inputValidationResult.Errors.Count() > 0 {
return writeGraphQLError(e.logger, w, inputValidationResult.Errors)
}
return nil, http.StatusOK
}
Cognitive complexity: 14, Cyclomatic complexity: 11
func (*EngineV3) Version
func (e *EngineV3) Version() EngineVersion {
return EngineVersionV3
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*GraphQLEngineTransport) RoundTrip
func (g *GraphQLEngineTransport) RoundTrip(request *http.Request) (res *http.Response, err error) {
switch g.transportType {
case GraphQLEngineTransportTypeProxyOnly:
val := GetProxyOnlyContextValue(request.Context())
if val != nil {
return g.handleProxyOnly(val, request)
}
}
return g.originalTransport.RoundTrip(request)
}
Cognitive complexity: 5, Cyclomatic complexity: 4
func (*GraphQLProxyOnlyContext) Response
func (g *GraphQLProxyOnlyContext) Response() *http.Response {
return g.upstreamResponse
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*complexityCheckerV1) DepthLimitExceeded
func (c *complexityCheckerV1) DepthLimitExceeded(r *http.Request, accessDefinition *ComplexityAccessDefinition) ComplexityFailReason {
if !c.depthLimitEnabled(accessDefinition) {
return ComplexityFailReasonNone
}
gqlRequest := c.ctxRetrieveRequest(r)
if gqlRequest == nil {
return ComplexityFailReasonNone
}
isIntrospectionQuery, err := gqlRequest.IsIntrospectionQuery()
if err != nil {
c.logger.Debug("error while checking for introspection query", abstractlogger.Error(err))
return ComplexityFailReasonInternalError
}
if isIntrospectionQuery {
return ComplexityFailReasonNone
}
complexityRes, err := gqlRequest.CalculateComplexity(graphql.DefaultComplexityCalculator, c.schema)
if err != nil {
c.logger.Error("error while calculating complexity of GraphQL request", abstractlogger.Error(err))
return ComplexityFailReasonInternalError
}
if complexityRes.Errors != nil && complexityRes.Errors.Count() > 0 {
c.logger.Error("error while calculating complexity of GraphQL request", abstractlogger.Error(complexityRes.Errors.ErrorByIndex(0)))
return ComplexityFailReasonInternalError
}
// do per query depth check
if len(accessDefinition.FieldAccessRights) == 0 {
if accessDefinition.Limit.MaxQueryDepth > 0 && complexityRes.Depth > accessDefinition.Limit.MaxQueryDepth {
c.logger.Debug("complexity of the request is higher than the allowed limit", abstractlogger.Int("maxQueryDepth", accessDefinition.Limit.MaxQueryDepth))
return ComplexityFailReasonDepthLimitExceeded
}
return ComplexityFailReasonNone
}
// do per query field depth check
for _, fieldComplexityRes := range complexityRes.PerRootField {
var (
fieldAccessDefinition ComplexityFieldAccessDefinition
hasPerFieldLimits bool
)
for _, fieldAccessRight := range accessDefinition.FieldAccessRights {
if fieldComplexityRes.TypeName != fieldAccessRight.TypeName {
continue
}
if fieldComplexityRes.FieldName != fieldAccessRight.FieldName {
continue
}
fieldAccessDefinition = fieldAccessRight
hasPerFieldLimits = true
break
}
if hasPerFieldLimits {
if greaterThanIntConsideringUnlimited(fieldComplexityRes.Depth, fieldAccessDefinition.Limits.MaxQueryDepth) {
c.logger.Debug(
"depth of the root field is higher than the allowed field limit",
abstractlogger.Int("depth", fieldComplexityRes.Depth),
abstractlogger.String("rootField", fmt.Sprintf("%s.%s", fieldAccessDefinition.TypeName, fieldAccessDefinition.FieldName)),
abstractlogger.Int("maxQueryDepth", fieldAccessDefinition.Limits.MaxQueryDepth),
)
return ComplexityFailReasonDepthLimitExceeded
}
continue
}
// favour global limit for query field
// have to increase resulting field depth by 1 to get a global depth
queryDepth := fieldComplexityRes.Depth + 1
if greaterThanIntConsideringUnlimited(queryDepth, accessDefinition.Limit.MaxQueryDepth) {
c.logger.Debug(
"depth of the root field is higher than the allowed global limit",
abstractlogger.Int("depth", queryDepth),
abstractlogger.String("rootField", fmt.Sprintf("%s.%s", fieldComplexityRes.TypeName, fieldComplexityRes.FieldName)),
abstractlogger.Int("maxQueryDepth", accessDefinition.Limit.MaxQueryDepth),
)
return ComplexityFailReasonDepthLimitExceeded
}
}
return ComplexityFailReasonNone
}
Cognitive complexity: 32, Cyclomatic complexity: 18
func (*complexityCheckerV2) DepthLimitExceeded
func (c *complexityCheckerV2) DepthLimitExceeded(r *http.Request, accessDefinition *ComplexityAccessDefinition) ComplexityFailReason {
if !c.depthLimitEnabled(accessDefinition) {
return ComplexityFailReasonNone
}
gqlRequest := c.ctxRetrieveRequest(r)
if gqlRequest == nil {
return ComplexityFailReasonNone
}
isIntrospectionQuery, err := gqlRequest.IsIntrospectionQuery()
if err != nil {
c.logger.Debug("error while checking for introspection query", abstractlogger.Error(err))
return ComplexityFailReasonInternalError
}
if isIntrospectionQuery {
return ComplexityFailReasonNone
}
complexityRes, err := gqlRequest.CalculateComplexity(graphqlv2.DefaultComplexityCalculator, c.schema)
if err != nil {
c.logger.Error("error while calculating complexity of GraphQL request", abstractlogger.Error(err))
return ComplexityFailReasonInternalError
}
if complexityRes.Errors != nil && complexityRes.Errors.Count() > 0 {
c.logger.Error("error while calculating complexity of GraphQL request", abstractlogger.Error(complexityRes.Errors.ErrorByIndex(0)))
return ComplexityFailReasonInternalError
}
// do per query depth check
if len(accessDefinition.FieldAccessRights) == 0 {
if accessDefinition.Limit.MaxQueryDepth > 0 && complexityRes.Depth > accessDefinition.Limit.MaxQueryDepth {
c.logger.Debug("complexity of the request is higher than the allowed limit", abstractlogger.Int("maxQueryDepth", accessDefinition.Limit.MaxQueryDepth))
return ComplexityFailReasonDepthLimitExceeded
}
return ComplexityFailReasonNone
}
// do per query field depth check
for _, fieldComplexityRes := range complexityRes.PerRootField {
var (
fieldAccessDefinition ComplexityFieldAccessDefinition
hasPerFieldLimits bool
)
for _, fieldAccessRight := range accessDefinition.FieldAccessRights {
if fieldComplexityRes.TypeName != fieldAccessRight.TypeName {
continue
}
if fieldComplexityRes.FieldName != fieldAccessRight.FieldName {
continue
}
fieldAccessDefinition = fieldAccessRight
hasPerFieldLimits = true
break
}
if hasPerFieldLimits {
if greaterThanIntConsideringUnlimited(fieldComplexityRes.Depth, fieldAccessDefinition.Limits.MaxQueryDepth) {
c.logger.Debug(
"depth of the root field is higher than the allowed field limit",
abstractlogger.Int("depth", fieldComplexityRes.Depth),
abstractlogger.String("rootField", fmt.Sprintf("%s.%s", fieldAccessDefinition.TypeName, fieldAccessDefinition.FieldName)),
abstractlogger.Int("maxQueryDepth", fieldAccessDefinition.Limits.MaxQueryDepth),
)
return ComplexityFailReasonDepthLimitExceeded
}
continue
}
// favour global limit for query field
// have to increase resulting field depth by 1 to get a global depth
queryDepth := fieldComplexityRes.Depth + 1
if greaterThanIntConsideringUnlimited(queryDepth, accessDefinition.Limit.MaxQueryDepth) {
c.logger.Debug(
"depth of the root field is higher than the allowed global limit",
abstractlogger.Int("depth", queryDepth),
abstractlogger.String("rootField", fmt.Sprintf("%s.%s", fieldComplexityRes.TypeName, fieldComplexityRes.FieldName)),
abstractlogger.Int("maxQueryDepth", accessDefinition.Limit.MaxQueryDepth),
)
return ComplexityFailReasonDepthLimitExceeded
}
}
return ComplexityFailReasonNone
}
Cognitive complexity: 32, Cyclomatic complexity: 18
func (*granularAccessCheckerV1) CheckGraphQLRequestFieldAllowance
func (g *granularAccessCheckerV1) CheckGraphQLRequestFieldAllowance(w http.ResponseWriter, r *http.Request, accessDefinition *GranularAccessDefinition) GraphQLGranularAccessResult {
gqlRequest := g.ctxRetrieveGraphQLRequest(r)
if gqlRequest == nil {
return GraphQLGranularAccessResult{FailReason: GranularAccessFailReasonNone}
}
isIntrospection, err := gqlRequest.IsIntrospectionQueryStrict()
if err != nil {
return GraphQLGranularAccessResult{
FailReason: GranularAccessFailReasonInternalError,
InternalErr: err,
}
}
if isIntrospection {
if accessDefinition.DisableIntrospection {
return GraphQLGranularAccessResult{FailReason: GranularAccessFailReasonIntrospectionDisabled}
}
// See TT-11260
//
// Introspection should be possible when Disable Introspection is turned off in policy settings,
// regardless of Allow List or Block List settings.
//
// Agreed solution: if Disable Introspection is turned off, then the Allow or Block list settings
// should be ignored, but only for the introspection query.
return GraphQLGranularAccessResult{FailReason: GranularAccessFailReasonNone}
}
if len(accessDefinition.AllowedTypes) != 0 {
fieldRestrictionList := graphql.FieldRestrictionList{
Kind: graphql.AllowList,
Types: g.convertGranularAccessTypeToGraphQLType(accessDefinition.AllowedTypes),
}
return g.validateFieldRestrictions(gqlRequest, fieldRestrictionList, g.schema)
}
if len(accessDefinition.RestrictedTypes) != 0 {
fieldRestrictionList := graphql.FieldRestrictionList{
Kind: graphql.BlockList,
Types: g.convertGranularAccessTypeToGraphQLType(accessDefinition.RestrictedTypes),
}
return g.validateFieldRestrictions(gqlRequest, fieldRestrictionList, g.schema)
}
// There are no restricted types. Every field is allowed access.
return GraphQLGranularAccessResult{FailReason: GranularAccessFailReasonNone}
}
Cognitive complexity: 19, Cyclomatic complexity: 7
func (*granularAccessCheckerV2) CheckGraphQLRequestFieldAllowance
func (g *granularAccessCheckerV2) CheckGraphQLRequestFieldAllowance(w http.ResponseWriter, r *http.Request, accessDefinition *GranularAccessDefinition) GraphQLGranularAccessResult {
gqlRequest := g.ctxRetrieveGraphQLRequest(r)
if gqlRequest == nil {
return GraphQLGranularAccessResult{FailReason: GranularAccessFailReasonNone}
}
isIntrospection, err := gqlRequest.IsIntrospectionQueryStrict()
if err != nil {
return GraphQLGranularAccessResult{
FailReason: GranularAccessFailReasonInternalError,
InternalErr: err,
}
}
if isIntrospection {
if accessDefinition.DisableIntrospection {
return GraphQLGranularAccessResult{FailReason: GranularAccessFailReasonIntrospectionDisabled}
}
// See TT-11260
//
// Introspection should be possible when Disable Introspection is turned off in policy settings,
// regardless of Allow List or Block List settings.
//
// Agreed solution: if Disable Introspection is turned off, then the Allow or Block list settings
// should be ignored, but only for the introspection query.
return GraphQLGranularAccessResult{FailReason: GranularAccessFailReasonNone}
}
if len(accessDefinition.AllowedTypes) != 0 {
fieldRestrictionList := graphqlv2.FieldRestrictionList{
Kind: graphqlv2.AllowList,
Types: g.convertGranularAccessTypeToGraphQLType(accessDefinition.AllowedTypes),
}
return g.validateFieldRestrictions(gqlRequest, fieldRestrictionList, g.schema)
}
if len(accessDefinition.RestrictedTypes) != 0 {
fieldRestrictionList := graphqlv2.FieldRestrictionList{
Kind: graphqlv2.BlockList,
Types: g.convertGranularAccessTypeToGraphQLType(accessDefinition.RestrictedTypes),
}
return g.validateFieldRestrictions(gqlRequest, fieldRestrictionList, g.schema)
}
// There are no restricted types. Every field is allowed access.
return GraphQLGranularAccessResult{FailReason: GranularAccessFailReasonNone}
}
Cognitive complexity: 19, Cyclomatic complexity: 7
func (*graphqlRequestProcessorV1) ProcessRequest
func (g *graphqlRequestProcessorV1) ProcessRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) (error, int) {
if r == nil {
g.logger.Error("request is nil")
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
gqlRequest := g.ctxRetrieveRequest(r)
normalizationResult, err := gqlRequest.Normalize(g.schema)
if err != nil {
g.logger.Error("error while normalizing GraphQL request", abstractlogger.Error(err))
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
if normalizationResult.Errors != nil && normalizationResult.Errors.Count() > 0 {
return writeGraphQLError(g.logger, w, normalizationResult.Errors)
}
validationResult, err := gqlRequest.ValidateForSchema(g.schema)
if err != nil {
g.logger.Error("error while validating GraphQL request", abstractlogger.Error(err))
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
if validationResult.Errors != nil && validationResult.Errors.Count() > 0 {
return writeGraphQLError(g.logger, w, validationResult.Errors)
}
inputValidationResult, err := gqlRequest.ValidateInput(g.schema)
if err != nil {
g.logger.Error("error while validating variables for request", abstractlogger.Error(err))
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
if inputValidationResult.Errors != nil && inputValidationResult.Errors.Count() > 0 {
return writeGraphQLError(g.logger, w, inputValidationResult.Errors)
}
return nil, http.StatusOK
}
Cognitive complexity: 14, Cyclomatic complexity: 11
func (*graphqlRequestProcessorWithOTelV1) ProcessRequest
func (g *graphqlRequestProcessorWithOTelV1) ProcessRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) (error, int) {
if r == nil {
g.logger.Error("request is nil")
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
g.otelExecutor.SetContext(ctx)
gqlRequest := g.ctxRetrieveRequest(r)
// normalization
err := g.otelExecutor.Normalize(gqlRequest)
if err != nil {
g.logger.Error("error while normalizing GraphqlRequest", abstractlogger.Error(err))
var reqErr graphql.RequestErrors
if errors.As(err, &reqErr) {
return writeGraphQLError(g.logger, w, reqErr)
}
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
// validation
err = g.otelExecutor.ValidateForSchema(gqlRequest)
if err != nil {
g.logger.Error("error while validating GraphQL request", abstractlogger.Error(err))
var reqErr graphql.RequestErrors
if errors.As(err, &reqErr) {
return writeGraphQLError(g.logger, w, reqErr)
}
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
// input validation
err = g.otelExecutor.InputValidation(gqlRequest)
if err != nil {
g.logger.Error("error while validating variables for request", abstractlogger.Error(err))
var reqErr graphql.RequestErrors
if errors.As(err, &reqErr) {
return writeGraphQLError(g.logger, w, reqErr)
}
return ProxyingRequestFailedErr, http.StatusInternalServerError
}
return nil, http.StatusOK
}
Cognitive complexity: 14, Cyclomatic complexity: 8
func (*reverseProxyPreHandlerV1) PreHandle
func (r *reverseProxyPreHandlerV1) PreHandle(params ReverseProxyParams) (reverseProxyType ReverseProxyType, err error) {
r.httpClient.Transport = NewGraphQLEngineTransport(
DetermineGraphQLEngineTransportType(r.apiDefinition),
params.RoundTripper,
r.newReusableBodyReadCloser,
params.HeadersConfig,
)
switch {
case params.IsCORSPreflight:
return ReverseProxyTypePreFlight, nil
case params.IsWebSocketUpgrade:
if params.NeedsEngine {
return ReverseProxyTypeWebsocketUpgrade, nil
}
default:
gqlRequest := r.ctxRetrieveGraphQLRequest(params.OutRequest)
if gqlRequest == nil {
err = errors.New("graphql request is nil")
return
}
gqlRequest.SetHeader(params.OutRequest.Header)
var isIntrospection bool
isIntrospection, err = gqlRequest.IsIntrospectionQuery()
if err != nil {
return
}
if isIntrospection {
return ReverseProxyTypeIntrospection, nil
}
if params.NeedsEngine {
return ReverseProxyTypeGraphEngine, nil
}
}
return ReverseProxyTypeNone, nil
}
Cognitive complexity: 14, Cyclomatic complexity: 9
func (*reverseProxyPreHandlerV2) PreHandle
func (r *reverseProxyPreHandlerV2) PreHandle(params ReverseProxyParams) (reverseProxyType ReverseProxyType, err error) {
r.httpClient.Transport = NewGraphQLEngineTransport(
DetermineGraphQLEngineTransportType(r.apiDefinition),
params.RoundTripper,
r.newReusableBodyReadCloser,
params.HeadersConfig,
)
switch {
case params.IsCORSPreflight:
return ReverseProxyTypePreFlight, nil
case params.IsWebSocketUpgrade:
if params.NeedsEngine {
return ReverseProxyTypeWebsocketUpgrade, nil
}
default:
gqlRequest := r.ctxRetrieveGraphQLRequest(params.OutRequest)
if gqlRequest == nil {
err = errors.New("graphql request is nil")
return
}
gqlRequest.SetHeader(params.OutRequest.Header)
var isIntrospection bool
isIntrospection, err = gqlRequest.IsIntrospectionQuery()
if err != nil {
return
}
if isIntrospection {
return ReverseProxyTypeIntrospection, nil
}
if params.NeedsEngine {
return ReverseProxyTypeGraphEngine, nil
}
}
return ReverseProxyTypeNone, nil
}
Cognitive complexity: 14, Cyclomatic complexity: 9
Private functions
func absLoggerLevel
absLoggerLevel (level logrus.Level) abstractlogger.Level
References: abstractlogger.DebugLevel, abstractlogger.ErrorLevel, abstractlogger.InfoLevel, abstractlogger.WarnLevel, logrus.DebugLevel, logrus.ErrorLevel, logrus.WarnLevel.
func additionalUpstreamHeaders
additionalUpstreamHeaders (logger abstractlogger.Logger, outreq *http.Request, apiDefinition *apidef.APIDefinition) http.Header
References: apidef.GraphQLExecutionModeExecutionEngine, apidef.GraphQLExecutionModeSupergraph, http.Header.
func complexityFailReasonAsHttpStatusCode
complexityFailReasonAsHttpStatusCode (failReason ComplexityFailReason) (error, int)
References: http.StatusForbidden, http.StatusInternalServerError, http.StatusOK.
func createAbstractLogrusLogger
createAbstractLogrusLogger (logger *logrus.Logger) *abstractlogger.LogrusLogger
References: abstractlogger.NewLogrusLogger.
func ctxGetData
ctxGetData (r *http.Request) map[string]interface{}
References: ctx.ContextData.
func granularAccessFailReasonAsHttpStatusCode
granularAccessFailReasonAsHttpStatusCode (logger abstractlogger.Logger, result *GraphQLGranularAccessResult, w http.ResponseWriter) (error, int)
References: abstractlogger.Error, header.ApplicationJSON, header.ContentType, http.StatusBadRequest, http.StatusForbidden, http.StatusInternalServerError, http.StatusOK.
func greaterThanIntConsideringUnlimited
greaterThanIntConsideringUnlimited (first,second int) bool
func headerStructToHeaderMap
headerStructToHeaderMap (headers []apidef.UDGGlobalHeader) map[string]string
func isProxyOnly
isProxyOnly (apiDefinition *apidef.APIDefinition) bool
References: apidef.GraphQLExecutionModeProxyOnly, apidef.GraphQLExecutionModeSubgraph.
func isSupergraph
isSupergraph (apiDefinition *apidef.APIDefinition) bool
References: apidef.GraphQLExecutionModeSupergraph.
func selectContentEncodingToBeUsed
selectContentEncodingToBeUsed selects the encoding value to be returned based on the IETF standards if acceptedEncoding is a list of comma separated strings br,gzip, deflate; then it selects the first supported one if it is a single value then it returns that value if no supported encoding is found, it returns the last value
selectContentEncodingToBeUsed (acceptedEncoding string) string
References: strings.Split, strings.TrimSpace.
func websocketConnWithUpgradeHeader
websocketConnWithUpgradeHeader (logger abstractlogger.Logger, params *ReverseProxyParams) (net.Conn, error)
References: abstractlogger.Error, header.SecWebSocketProtocol, http.Header.
func writeGraphQLError
writeGraphQLError (logger abstractlogger.Logger, w http.ResponseWriter, errors graphql.Errors) (error, int)
References: abstractlogger.Error, header.ApplicationJSON, header.ContentType, http.StatusBadRequest.
func handoverRequestToGraphQLExecutionEngine
handoverRequestToGraphQLExecutionEngine (gqlRequest *graphql.Request, outreq *http.Request) (*http.Response, bool, error)
References: context.Background, errors.New, graphql.ExecutionOptions, graphql.ExecutionResult.
func handoverWebSocketConnectionToGraphQLExecutionEngine
handoverWebSocketConnectionToGraphQLExecutionEngine (params *ReverseProxyParams) (*http.Response, bool, error)
References: abstractlogger.Error, gqlwebsocket.Handle, gqlwebsocket.WithLogger, gqlwebsocket.WithProtocolFromRequestHeaders, subscription.ExecutorPool, subscription.NewExecutorV1Pool.
func handoverRequestToGraphQLExecutionEngine
handoverRequestToGraphQLExecutionEngine (gqlRequest *graphql.Request, outreq *http.Request) (*http.Response, bool, error)
References: context.Background, errors.New, graphql.ExecutionOptionsV2, graphql.NewEngineResultWriter, graphql.WithAfterFetchHook, graphql.WithBeforeFetchHook, graphql.WithHeaderModifier, http.Header, http.StatusBadRequest, http.StatusOK, httpclient.AcceptEncodingHeader, httpclient.ContentEncodingHeader, otel.ContextWithSpan, otel.SpanFromContext.
func handoverWebSocketConnectionToGraphQLExecutionEngine
handoverWebSocketConnectionToGraphQLExecutionEngine (params *ReverseProxyParams) (*http.Response, bool, error)
References: abstractlogger.Error, gqlwebsocket.Handle, gqlwebsocket.WithLogger, gqlwebsocket.WithProtocolFromRequestHeaders, subscription.ExecutorPool, subscription.NewExecutorV2Pool, subscription.NewInitialHttpRequestContext, subscription.WithExecutorV2HeaderModifier.
func handoverRequestToGraphQLExecutionEngine
handoverRequestToGraphQLExecutionEngine (gqlRequest *graphqlv2.Request, outreq *http.Request) (*http.Response, bool, error)
References: context.Background, errors.New, graphqlv2.ExecutionOptionsV2, graphqlv2.NewEngineResultWriter, graphqlv2.WithHeaderModifier, http.Header, http.StatusBadRequest, http.StatusOK, httpclientv2.AcceptEncodingHeader, httpclientv2.ContentEncodingHeader, otel.ContextWithSpan, otel.SpanFromContext.
func handoverWebSocketConnectionToGraphQLExecutionEngine
handoverWebSocketConnectionToGraphQLExecutionEngine (params *ReverseProxyParams) (*http.Response, bool, error)
References: abstractlogger.Error, gqlwebsocketv2.Handle, gqlwebsocketv2.WithLogger, gqlwebsocketv2.WithProtocolFromRequestHeaders, subscriptionv2.ExecutorPool, subscriptionv2.NewExecutorV2Pool, subscriptionv2.NewInitialHttpRequestContext, subscriptionv2.WithExecutorV2HeaderModifier.
func applyRequestHeadersRewriteRules
applyRequestHeadersRewriteRules (r *http.Request)
References: http.Request.
func handleProxyOnly
handleProxyOnly (proxyOnlyValues *GraphQLProxyOnlyContextValues, request *http.Request) (*http.Response, error)
References: bytes.NewReader, http.StatusBadRequest, io.NopCloser, io.ReadAll.
func setProxyOnlyHeaders
setProxyOnlyHeaders (proxyOnlyValues *GraphQLProxyOnlyContextValues, r *http.Request)
func depthLimitEnabled
depthLimitEnabled (accessDefinition *ComplexityAccessDefinition) bool
func depthLimitEnabled
depthLimitEnabled (accessDefinition *ComplexityAccessDefinition) bool
func convertGranularAccessTypeToGraphQLType
convertGranularAccessTypeToGraphQLType (accessTypes []GranularAccessType) []graphql.Type
References: graphql.Type.
func validateFieldRestrictions
validateFieldRestrictions (gqlRequest *graphql.Request, fieldRestrictionList graphql.FieldRestrictionList, schema *graphql.Schema) GraphQLGranularAccessResult
References: graphql.DefaultFieldsValidator.
func writeErrorResponse
writeErrorResponse (w io.Writer, providedErr error) (int, error)
References: graphql.RequestErrorsFromError.
func convertGranularAccessTypeToGraphQLType
convertGranularAccessTypeToGraphQLType (accessTypes []GranularAccessType) []graphqlv2.Type
References: graphqlv2.Type.
func validateFieldRestrictions
validateFieldRestrictions (gqlRequest *graphqlv2.Request, fieldRestrictionList graphqlv2.FieldRestrictionList, schema *graphqlv2.Schema) GraphQLGranularAccessResult
References: graphqlv2.DefaultFieldsValidator.
func writeErrorResponse
writeErrorResponse (w io.Writer, providedErr error) (int, error)
References: graphqlv2.RequestErrorsFromError.
func createExecutionEngine
createExecutionEngine (params createExecutionEngineV1Params) (*graphql.ExecutionEngine, error)
References: abstractlogger.Error, abstractlogger.NoopLogger, datasource.Hooks, datasource.PlannerConfiguration, datasource.SchemaDataSourcePlannerConfig, datasource.SchemaDataSourcePlannerFactoryFactory, datasource.SourceConfig, datasource.TypeFieldConfiguration, fmt.Sprintf, graphql.DataSourceGraphqlOptions, graphql.DataSourceHttpJsonOptions, graphql.NewExecutionEngine, json.Marshal, json.RawMessage.
func handleIntrospection
handleIntrospection (schema *graphql.Schema) (*http.Response, bool, error)
References: graphql.ExecutionResult, graphql.SchemaIntrospection.
func headerModifier
headerModifier (additionalHeaders http.Header) postprocess.HeaderModifier
References: http.Header.
func parseSchema
parseSchema (schema string) (*graphql.Schema, error)
References: fmt.Errorf, graphql.NewSchemaFromString.
func returnErrorsFromUpstream
returnErrorsFromUpstream (proxyOnlyCtx *GraphQLProxyOnlyContextValues, resultWriter *graphql.EngineResultWriter, seekReadCloser SeekReadCloserFunc) error
References: io.ReadAll, jsonparser.Set.
func handleIntrospection
handleIntrospection (schema *graphqlv2.Schema) (*http.Response, bool, error)
References: astparser.ParseGraphqlDocumentBytes, bytes.Buffer, http.Header, http.Response, introspection.Data, introspection.NewGenerator, io.NopCloser, json.NewEncoder, operationreport.Report.
func headerModifier
headerModifier (outreq *http.Request, additionalHeaders http.Header, variableReplacer TykVariableReplacer) postprocessv2.HeaderModifier
References: http.Header.
func parseSchema
parseSchema (schema string) (*graphqlv2.Schema, error)
References: fmt.Errorf, graphqlv2.NewSchemaFromString.
func returnErrorsFromUpstream
returnErrorsFromUpstream (proxyOnlyCtx *GraphQLProxyOnlyContextValues, resultWriter *graphqlv2.EngineResultWriter, seekReadCloser SeekReadCloserFunc) error
References: io.ReadAll, jsonparser.Set.
Tests
Files: 7. Third party imports: 5. Imports from organisation: 3. Tests: 19. Benchmarks: 0.
Vars
var testIntrospectionQuery = `query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}`
var testIntrospectionResultEngineV1 = `{"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":null,"subscriptionType":null,"types":[{"kind":"OBJECT","name":"Query","description":"","fields":[{"name":"hello","description":"","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"helloName","description":"","args":[{"name":"name","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"Int","description":"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"Float","description":"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"String","description":"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"Boolean","description":"The 'Boolean' scalar type represents 'true' or 'false' .","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"ID","description":"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID.","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]}],"directives":[{"name":"include","description":"Directs the executor to include this field or fragment only when the argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Included when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}],"isRepeatable":false},{"name":"skip","description":"Directs the executor to skip this field or fragment when the argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Skipped when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}],"isRepeatable":false},{"name":"deprecated","description":"Marks an element of a GraphQL schema as no longer supported.","locations":["FIELD_DEFINITION","ENUM_VALUE"],"args":[{"name":"reason","description":"Explains why this element was deprecated, usually also including a suggestion\n for how to access supported similar data. Formatted in\n [Markdown](https://daringfireball.net/projects/markdown/).","type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":"\"No longer supported\""}],"isRepeatable":false}]}}}
`
var testSchemaEngineV1 = `
type Query {
hello: String
helloName(name: String!): String
}
`
var testSchemaEngineV2 = `
type Query {
hello: String
helloName(name: String!): String
}
`
var testSchemaNestedEngineV1 = `
type Query {
countries: [Country]
}
type Country {
continent: Continent
}
type Continent {
countries: [Country]
}`
Types
MockComplexityChecker
MockComplexityChecker is a mock of ComplexityChecker interface.
| Field name | Field type | Comment |
|---|---|---|
| ctrl |
|
No comment on field. |
| recorder |
|
No comment on field. |
type MockComplexityChecker struct {
ctrl *gomock.Controller
recorder *MockComplexityCheckerMockRecorder
}
MockComplexityCheckerMockRecorder
MockComplexityCheckerMockRecorder is the mock recorder for MockComplexityChecker.
| Field name | Field type | Comment |
|---|---|---|
| mock |
|
No comment on field. |
type MockComplexityCheckerMockRecorder struct {
mock *MockComplexityChecker
}
MockEngine
MockEngine is a mock of Engine interface.
| Field name | Field type | Comment |
|---|---|---|
| ctrl |
|
No comment on field. |
| recorder |
|
No comment on field. |
type MockEngine struct {
ctrl *gomock.Controller
recorder *MockEngineMockRecorder
}
MockEngineMockRecorder
MockEngineMockRecorder is the mock recorder for MockEngine.
| Field name | Field type | Comment |
|---|---|---|
| mock |
|
No comment on field. |
type MockEngineMockRecorder struct {
mock *MockEngine
}
MockGranularAccessChecker
MockGranularAccessChecker is a mock of GranularAccessChecker interface.
| Field name | Field type | Comment |
|---|---|---|
| ctrl |
|
No comment on field. |
| recorder |
|
No comment on field. |
type MockGranularAccessChecker struct {
ctrl *gomock.Controller
recorder *MockGranularAccessCheckerMockRecorder
}
MockGranularAccessCheckerMockRecorder
MockGranularAccessCheckerMockRecorder is the mock recorder for MockGranularAccessChecker.
| Field name | Field type | Comment |
|---|---|---|
| mock |
|
No comment on field. |
type MockGranularAccessCheckerMockRecorder struct {
mock *MockGranularAccessChecker
}
MockGraphQLRequestProcessor
MockGraphQLRequestProcessor is a mock of GraphQLRequestProcessor interface.
| Field name | Field type | Comment |
|---|---|---|
| ctrl |
|
No comment on field. |
| recorder |
|
No comment on field. |
type MockGraphQLRequestProcessor struct {
ctrl *gomock.Controller
recorder *MockGraphQLRequestProcessorMockRecorder
}
MockGraphQLRequestProcessorMockRecorder
MockGraphQLRequestProcessorMockRecorder is the mock recorder for MockGraphQLRequestProcessor.
| Field name | Field type | Comment |
|---|---|---|
| mock |
|
No comment on field. |
type MockGraphQLRequestProcessorMockRecorder struct {
mock *MockGraphQLRequestProcessor
}
MockReverseProxyPreHandler
MockReverseProxyPreHandler is a mock of ReverseProxyPreHandler interface.
| Field name | Field type | Comment |
|---|---|---|
| ctrl |
|
No comment on field. |
| recorder |
|
No comment on field. |
type MockReverseProxyPreHandler struct {
ctrl *gomock.Controller
recorder *MockReverseProxyPreHandlerMockRecorder
}
MockReverseProxyPreHandlerMockRecorder
MockReverseProxyPreHandlerMockRecorder is the mock recorder for MockReverseProxyPreHandler.
| Field name | Field type | Comment |
|---|---|---|
| mock |
|
No comment on field. |
type MockReverseProxyPreHandlerMockRecorder struct {
mock *MockReverseProxyPreHandler
}
engineV1Mocks
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| controller |
|
No comment on field. |
| requestProcessor |
|
No comment on field. |
| complexityChecker |
|
No comment on field. |
| granularAccessChecker |
|
No comment on field. |
| reverseProxyPreHandler |
|
No comment on field. |
type engineV1Mocks struct {
controller *gomock.Controller
requestProcessor *MockGraphQLRequestProcessor
complexityChecker *MockComplexityChecker
granularAccessChecker *MockGranularAccessChecker
reverseProxyPreHandler *MockReverseProxyPreHandler
}
engineV2Mocks
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| controller |
|
No comment on field. |
| requestProcessor |
|
No comment on field. |
| complexityChecker |
|
No comment on field. |
| granularAccessChecker |
|
No comment on field. |
| reverseProxyPreHandler |
|
No comment on field. |
type engineV2Mocks struct {
controller *gomock.Controller
requestProcessor *MockGraphQLRequestProcessor
complexityChecker *MockComplexityChecker
granularAccessChecker *MockGranularAccessChecker
reverseProxyPreHandler *MockReverseProxyPreHandler
}
nopRoundTripper
This type doesn't have documentation.
type nopRoundTripper struct{}
testComplexityCheckerV1Option
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type testComplexityCheckerV1Option func(*testComplexityCheckerV1Options)
testComplexityCheckerV1Options
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| schema |
|
No comment on field. |
type testComplexityCheckerV1Options struct {
schema string
}
testEngineV1Option
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type testEngineV1Option func(*testEngineV1Options)
testEngineV1Options
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| targetURL |
|
No comment on field. |
| executionMode |
|
No comment on field. |
type testEngineV1Options struct {
targetURL string
executionMode apidef.GraphQLExecutionMode
}
testEngineV2Option
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type testEngineV2Option func(*testEngineV2Options)
testEngineV2Options
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| targetURL |
|
No comment on field. |
| apiDefinition |
|
No comment on field. |
| otelConfig |
|
No comment on field. |
type testEngineV2Options struct {
targetURL string
apiDefinition *apidef.APIDefinition
otelConfig EngineV2OTelConfig
}