-
Notifications
You must be signed in to change notification settings - Fork 253
Expand file tree
/
Copy pathconfig.go
More file actions
1502 lines (1266 loc) · 80.7 KB
/
Copy pathconfig.go
File metadata and controls
1502 lines (1266 loc) · 80.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
package config
import (
"errors"
"fmt"
"os"
"strings"
"time"
"github.com/caarlos0/env/v11"
"github.com/goccy/go-yaml"
"github.com/wundergraph/cosmo/router/internal/unique"
"github.com/wundergraph/cosmo/router/internal/yamlmerge"
"github.com/wundergraph/cosmo/router/pkg/otel/otelconfig"
"go.uber.org/zap/zapcore"
)
const (
DefaultConfigPath = "config.yaml"
)
type Graph struct {
// Token is required if no router config path is provided
Token string `yaml:"token,omitempty" env:"GRAPH_API_TOKEN"`
// SignKey is used to validate the signature of the received config. The same key is used to publish the subgraph in sign mode.
SignKey string `yaml:"sign_key,omitempty" env:"GRAPH_CONFIG_SIGN_KEY"`
}
type CustomStaticAttribute struct {
Key string `yaml:"key"`
Value string `yaml:"value"`
}
type CustomDynamicAttribute struct {
RequestHeader string `yaml:"request_header,omitempty"`
ContextField string `yaml:"context_field,omitempty"`
ResponseHeader string `yaml:"response_header,omitempty"`
Expression string `yaml:"expression,omitempty"` // only implemented by CustomAttribute in Metrics and Telemetry and Router Access Logs
}
type CustomAttribute struct {
Key string `yaml:"key"`
Default string `yaml:"default"`
ValueFrom *CustomDynamicAttribute `yaml:"value_from,omitempty"`
}
type TracingExporterConfig struct {
BatchTimeout time.Duration `yaml:"batch_timeout,omitempty" envDefault:"10s"`
ExportTimeout time.Duration `yaml:"export_timeout,omitempty" envDefault:"30s"`
}
type TracingGlobalFeatures struct {
ExportGraphQLVariables bool `yaml:"export_graphql_variables" envDefault:"false" env:"TRACING_EXPORT_GRAPHQL_VARIABLES"`
WithNewRoot bool `yaml:"with_new_root" envDefault:"false" env:"TRACING_WITH_NEW_ROOT"`
}
type TracingExporter struct {
Disabled bool `yaml:"disabled"`
Exporter otelconfig.Exporter `yaml:"exporter,omitempty"`
Endpoint string `yaml:"endpoint,omitempty"`
HTTPPath string `yaml:"path,omitempty" envDefault:"/v1/traces"`
Headers map[string]string `yaml:"headers,omitempty"`
TracingExporterConfig `yaml:",inline"`
}
type ResponseTraceHeader struct {
Enabled bool `yaml:"enabled"`
HeaderName string `yaml:"header_name" envDefault:"x-wg-trace-id"`
}
type SanitizeUTF8Config struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"ENABLED"`
LogSanitizations bool `yaml:"log_sanitizations" envDefault:"false" env:"LOG_SANITIZATIONS"`
}
type Tracing struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"TRACING_ENABLED"`
SamplingRate float64 `yaml:"sampling_rate" envDefault:"1" env:"TRACING_SAMPLING_RATE"`
ParentBasedSampler bool `yaml:"parent_based_sampler" envDefault:"true" env:"TRACING_PARENT_BASED_SAMPLER"`
Exporters []TracingExporter `yaml:"exporters"`
Propagation PropagationConfig `yaml:"propagation"`
ResponseTraceHeader ResponseTraceHeader `yaml:"response_trace_id"`
Attributes []CustomAttribute `yaml:"attributes"`
OperationContentAttributes bool `yaml:"operation_content_attributes" envDefault:"false" env:"TRACING_OPERATION_CONTENT_ATTRIBUTES"`
TracingGlobalFeatures `yaml:",inline"`
// SanitizeUTF8 configures sanitization of invalid UTF-8 sequences in span attribute values
SanitizeUTF8 SanitizeUTF8Config `yaml:"sanitize_utf8" envPrefix:"TRACING_SANITIZE_UTF8_"`
}
type PropagationConfig struct {
TraceContext bool `yaml:"trace_context" envDefault:"true"`
Jaeger bool `yaml:"jaeger"`
B3 bool `yaml:"b3"`
Baggage bool `yaml:"baggage"`
Datadog bool `yaml:"datadog"`
}
type EngineStats struct {
Subscriptions bool `yaml:"subscriptions" envDefault:"false" env:"ENGINE_STATS_SUBSCRIPTIONS"`
}
type CostStats struct {
EstimatedEnabled bool `yaml:"estimated_enabled" envDefault:"false" env:"ESTIMATED_ENABLED"`
ActualEnabled bool `yaml:"actual_enabled" envDefault:"false" env:"ACTUAL_ENABLED"`
}
type Prometheus struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"PROMETHEUS_ENABLED"`
Path string `yaml:"path" envDefault:"/metrics" env:"PROMETHEUS_HTTP_PATH"`
ListenAddr string `yaml:"listen_addr" envDefault:"127.0.0.1:8088" env:"PROMETHEUS_LISTEN_ADDR"`
GraphqlCache bool `yaml:"graphql_cache" envDefault:"false" env:"PROMETHEUS_GRAPHQL_CACHE"`
ConnectionStats bool `yaml:"connection_stats" envDefault:"false" env:"PROMETHEUS_CONNECTION_STATS"`
Streams bool `yaml:"streams" envDefault:"false" env:"PROMETHEUS_STREAM"`
EngineStats EngineStats `yaml:"engine_stats" envPrefix:"PROMETHEUS_"`
CostStats CostStats `yaml:"cost_stats" envPrefix:"PROMETHEUS_COST_STATS_"`
CircuitBreaker bool `yaml:"circuit_breaker" envDefault:"false" env:"PROMETHEUS_CIRCUIT_BREAKER"`
ExcludeMetrics RegExArray `yaml:"exclude_metrics,omitempty" env:"PROMETHEUS_EXCLUDE_METRICS"`
ExcludeMetricLabels RegExArray `yaml:"exclude_metric_labels,omitempty" env:"PROMETHEUS_EXCLUDE_METRIC_LABELS"`
ExcludeScopeInfo bool `yaml:"exclude_scope_info" envDefault:"false" env:"PROMETHEUS_EXCLUDE_SCOPE_INFO"`
SchemaFieldUsage PrometheusSchemaFieldUsage `yaml:"schema_usage" envPrefix:"PROMETHEUS_SCHEMA_FIELD_USAGE_"`
}
type PrometheusSchemaFieldUsage struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"ENABLED"`
IncludeOperationSha bool `yaml:"include_operation_sha" envDefault:"false" env:"INCLUDE_OPERATION_SHA"`
Exporter PrometheusSchemaFieldUsageExporter `yaml:"exporter" envPrefix:"EXPORTER_"`
}
type PrometheusSchemaFieldUsageExporter struct {
BatchSize int `yaml:"batch_size" envDefault:"4096" env:"BATCH_SIZE"`
QueueSize int `yaml:"queue_size" envDefault:"12800" env:"QUEUE_SIZE"`
Interval time.Duration `yaml:"interval" envDefault:"2s" env:"INTERVAL"`
ExportTimeout time.Duration `yaml:"export_timeout" envDefault:"10s" env:"EXPORT_TIMEOUT"`
}
type MetricsOTLPExporter struct {
Disabled bool `yaml:"disabled"`
Exporter otelconfig.Exporter `yaml:"exporter" envDefault:"http"`
Endpoint string `yaml:"endpoint"`
HTTPPath string `yaml:"path" envDefault:"/v1/metrics"`
Headers map[string]string `yaml:"headers"`
Temporality otelconfig.ExporterTemporality `yaml:"temporality"`
}
type Metrics struct {
Attributes []CustomAttribute `yaml:"attributes"`
OTLP MetricsOTLP `yaml:"otlp"`
Prometheus Prometheus `yaml:"prometheus"`
CardinalityLimit int `yaml:"experiment_cardinality_limit" envDefault:"2000" env:"METRICS_EXPERIMENT_CARDINALITY_LIMIT"`
}
type MetricsLogExporter struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"ENABLED"`
ExcludeMetrics RegExArray `yaml:"exclude_metrics,omitempty" env:"EXCLUDE_METRICS"`
IncludeMetrics RegExArray `yaml:"include_metrics,omitempty" env:"INCLUDE_METRICS"`
}
type MetricsOTLP struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"METRICS_OTLP_ENABLED"`
RouterRuntime bool `yaml:"router_runtime" envDefault:"true" env:"METRICS_OTLP_ROUTER_RUNTIME"`
GraphqlCache bool `yaml:"graphql_cache" envDefault:"false" env:"METRICS_OTLP_GRAPHQL_CACHE"`
ConnectionStats bool `yaml:"connection_stats" envDefault:"false" env:"METRICS_OTLP_CONNECTION_STATS"`
EngineStats EngineStats `yaml:"engine_stats" envPrefix:"METRICS_OTLP_"`
CostStats CostStats `yaml:"cost_stats" envPrefix:"METRICS_OTLP_COST_STATS_"`
CircuitBreaker bool `yaml:"circuit_breaker" envDefault:"false" env:"METRICS_OTLP_CIRCUIT_BREAKER"`
Streams bool `yaml:"streams" envDefault:"false" env:"METRICS_OTLP_STREAM"`
ExcludeMetrics RegExArray `yaml:"exclude_metrics,omitempty" env:"METRICS_OTLP_EXCLUDE_METRICS"`
ExcludeMetricLabels RegExArray `yaml:"exclude_metric_labels,omitempty" env:"METRICS_OTLP_EXCLUDE_METRIC_LABELS"`
Exporters []MetricsOTLPExporter `yaml:"exporters"`
LogExporter MetricsLogExporter `yaml:"log_exporter" envPrefix:"METRICS_OTLP_LOG_EXPORTER_"`
}
type Telemetry struct {
ServiceName string `yaml:"service_name" envDefault:"cosmo-router" env:"TELEMETRY_SERVICE_NAME"`
Attributes []CustomAttribute `yaml:"attributes"`
ResourceAttributes []CustomStaticAttribute `yaml:"resource_attributes"`
Tracing Tracing `yaml:"tracing"`
Metrics Metrics `yaml:"metrics"`
}
type CORS struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"CORS_ENABLED"`
AllowOrigins []string `yaml:"allow_origins" envDefault:"*" env:"CORS_ALLOW_ORIGINS"`
AllowMethods []string `yaml:"allow_methods" envDefault:"HEAD,GET,POST" env:"CORS_ALLOW_METHODS"`
AllowHeaders []string `yaml:"allow_headers" envDefault:"Origin,Content-Length,Content-Type" env:"CORS_ALLOW_HEADERS"`
AllowCredentials bool `yaml:"allow_credentials" envDefault:"true" env:"CORS_ALLOW_CREDENTIALS"`
MaxAge time.Duration `yaml:"max_age" envDefault:"5m" env:"CORS_MAX_AGE"`
}
type TrafficShapingRules struct {
// All is a set of rules that apply to all requests
All GlobalSubgraphRequestRule `yaml:"all"`
// Apply to requests from clients to the router
Router RouterTrafficConfiguration `yaml:"router"`
// Subgraphs is a set of rules that apply to requests from the router to subgraphs. The key is the subgraph name.
Subgraphs map[string]GlobalSubgraphRequestRule `yaml:"subgraphs,omitempty"`
}
type FileUpload struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"FILE_UPLOAD_ENABLED"`
MaxFileSizeBytes BytesString `yaml:"max_file_size" envDefault:"50MB" env:"FILE_UPLOAD_MAX_FILE_SIZE"`
MaxFiles int `yaml:"max_files" envDefault:"10" env:"FILE_UPLOAD_MAX_FILES"`
}
type RouterTrafficConfiguration struct {
// MaxRequestBodyBytes is the maximum size of the request body in bytes
MaxRequestBodyBytes BytesString `yaml:"max_request_body_size" envDefault:"5MB"`
// MaxHeaderBytes is the maximum size of the request headers in bytes
MaxHeaderBytes BytesString `yaml:"max_header_bytes" envDefault:"0MiB" env:"MAX_HEADER_BYTES"`
// DecompressionEnabled is the configuration for request compression
DecompressionEnabled bool `yaml:"decompression_enabled" envDefault:"true"`
// ResponseCompressionMinSize is the minimum size of the response body in bytes to enable response compression
ResponseCompressionMinSize BytesString `yaml:"response_compression_min_size" envDefault:"4KiB" env:"RESPONSE_COMPRESSION_MIN_SIZE"`
}
type GlobalSubgraphRequestRule struct {
BackoffJitterRetry BackoffJitterRetry `yaml:"retry"`
CircuitBreaker CircuitBreaker `yaml:"circuit_breaker"`
// See https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/
RequestTimeout *time.Duration `yaml:"request_timeout,omitempty" envDefault:"60s"`
DialTimeout *time.Duration `yaml:"dial_timeout,omitempty" envDefault:"30s"`
ResponseHeaderTimeout *time.Duration `yaml:"response_header_timeout,omitempty" envDefault:"0s"`
ExpectContinueTimeout *time.Duration `yaml:"expect_continue_timeout,omitempty" envDefault:"0s"`
TLSHandshakeTimeout *time.Duration `yaml:"tls_handshake_timeout,omitempty" envDefault:"10s"`
KeepAliveIdleTimeout *time.Duration `yaml:"keep_alive_idle_timeout,omitempty" envDefault:"90s"`
KeepAliveProbeInterval *time.Duration `yaml:"keep_alive_probe_interval,omitempty" envDefault:"30s"`
// Connection configuration
MaxConnsPerHost *int `yaml:"max_conns_per_host,omitempty" envDefault:"100"`
MaxIdleConns *int `yaml:"max_idle_conns,omitempty" envDefault:"1024"`
MaxIdleConnsPerHost *int `yaml:"max_idle_conns_per_host,omitempty" envDefault:"20"`
}
type SubgraphTrafficRequestRule struct {
RequestTimeout time.Duration `yaml:"request_timeout,omitempty" envDefault:"60s"`
}
type CircuitBreaker struct {
Enabled bool `yaml:"enabled" envDefault:"false"`
ErrorThresholdPercentage int64 `yaml:"error_threshold_percentage" envDefault:"50"`
RequestThreshold int64 `yaml:"request_threshold" envDefault:"20"`
SleepWindow time.Duration `yaml:"sleep_window" envDefault:"5s"`
HalfOpenAttempts int64 `yaml:"half_open_attempts" envDefault:"1"`
RequiredSuccessfulAttempts int64 `yaml:"required_successful" envDefault:"1"`
RollingDuration time.Duration `yaml:"rolling_duration" envDefault:"10s"`
NumBuckets int `yaml:"num_buckets" envDefault:"10"`
ExecutionTimeout time.Duration `yaml:"execution_timeout" envDefault:"60s"`
MaxConcurrentRequests int64 `yaml:"max_concurrent_requests" envDefault:"-1"`
}
type GraphqlMetrics struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"GRAPHQL_METRICS_ENABLED"`
CollectorEndpoint string `yaml:"collector_endpoint" envDefault:"https://cosmo-metrics.wundergraph.com" env:"GRAPHQL_METRICS_COLLECTOR_ENDPOINT"`
}
type BackoffJitterRetry struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"RETRY_ENABLED"`
Algorithm string `yaml:"algorithm" envDefault:"backoff_jitter" env:"RETRY_ALGORITHM"`
MaxAttempts int `yaml:"max_attempts" envDefault:"5" env:"RETRY_MAX_ATTEMPTS"`
MaxDuration time.Duration `yaml:"max_duration" envDefault:"10s" env:"RETRY_MAX_DURATION"`
Interval time.Duration `yaml:"interval" envDefault:"3s" env:"RETRY_INTERVAL"`
Expression string `yaml:"expression,omitempty" env:"RETRY_EXPRESSION" envDefault:"IsRetryableStatusCode() || IsConnectionError() || IsTimeout()"`
}
type SubgraphCacheControlRule struct {
Name string `yaml:"name"`
Value string `yaml:"value"`
}
type CacheControlPolicy struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"CACHE_CONTROL_POLICY_ENABLED"`
Value string `yaml:"value" env:"CACHE_CONTROL_POLICY_VALUE"`
Subgraphs []SubgraphCacheControlRule `yaml:"subgraphs,omitempty"`
}
type HeaderRules struct {
// All is a set of rules that apply to all requests
All *GlobalHeaderRule `yaml:"all,omitempty"`
Subgraphs map[string]*GlobalHeaderRule `yaml:"subgraphs,omitempty"`
CookieWhitelist []string `yaml:"cookie_whitelist,omitempty"`
Router RouterHeaderRules `yaml:"router,omitempty"`
}
type RouterHeaderRules struct {
// All is a set of rules that apply to all response
Response []*RouterResponseHeaderRule `yaml:"response,omitempty"`
}
type GlobalHeaderRule struct {
// Request is a set of rules that apply to requests
Request []*RequestHeaderRule `yaml:"request,omitempty"`
Response []*ResponseHeaderRule `yaml:"response,omitempty"`
}
type HeaderRuleOperation string
const (
HeaderRuleOperationPropagate HeaderRuleOperation = "propagate"
HeaderRuleOperationSet HeaderRuleOperation = "set"
)
type HeaderRule interface {
GetOperation() HeaderRuleOperation
GetMatching() string
}
type RequestHeaderRule struct {
// Operation describes the header operation to perform e.g. "propagate"
Operation HeaderRuleOperation `yaml:"op"`
// Propagate options
// Matching is the regex to match the header name against
Matching string `yaml:"matching"`
NegateMatch bool `yaml:"negate_match,omitempty"`
// Named is the exact header name to match
Named string `yaml:"named"`
// Rename renames the header's key to the provided value
Rename string `yaml:"rename,omitempty"`
// Default is the default value to set if the header is not present
Default string `yaml:"default"`
// Set header options
// Name is the name of the header to set
Name string `yaml:"name"`
// Value is the static value to set for the header
Value string `yaml:"value"`
// Expression is the Expr Lang expression to evaluate for dynamic header values
Expression string `yaml:"expression"`
// ValueFrom is deprecated in favor of Expression. Use Expression instead.
ValueFrom *CustomDynamicAttribute `yaml:"value_from,omitempty"`
}
func (r *RequestHeaderRule) GetOperation() HeaderRuleOperation {
return r.Operation
}
func (r *RequestHeaderRule) GetMatching() string {
return r.Matching
}
type ResponseHeaderRuleAlgorithm string
const (
// ResponseHeaderRuleAlgorithmFirstWrite propagates the first response header from a subgraph to the client
ResponseHeaderRuleAlgorithmFirstWrite ResponseHeaderRuleAlgorithm = "first_write"
// ResponseHeaderRuleAlgorithmLastWrite propagates the last response header from a subgraph to the client
ResponseHeaderRuleAlgorithmLastWrite ResponseHeaderRuleAlgorithm = "last_write"
// ResponseHeaderRuleAlgorithmAppend appends all response headers from all subgraphs to a comma separated list of values in the client response
ResponseHeaderRuleAlgorithmAppend ResponseHeaderRuleAlgorithm = "append"
// ResponseHeaderRuleAlgorithmMostRestrictiveCacheControl propagates the most restrictive cache control header from all subgraph responses to the client
ResponseHeaderRuleAlgorithmMostRestrictiveCacheControl ResponseHeaderRuleAlgorithm = "most_restrictive_cache_control"
)
type RouterResponseHeaderRule struct {
// Set header options
Name string `yaml:"name"`
Expression string `yaml:"expression"`
}
type ResponseHeaderRule struct {
// Operation describes the header operation to perform e.g. "propagate"
Operation HeaderRuleOperation `yaml:"op"`
// Matching is the regex to match the header name against
Matching string `yaml:"matching"`
NegateMatch bool `yaml:"negate_match,omitempty"`
// Named is the exact header name to match
Named string `yaml:"named"`
// Rename renames the header's key to the provided value
Rename string `yaml:"rename,omitempty"`
// Default is the default value to set if the header is not present
Default string `yaml:"default"`
// Algorithm is the algorithm to use when multiple headers are present
Algorithm ResponseHeaderRuleAlgorithm `yaml:"algorithm,omitempty"`
// Set header options
// Name is the name of the header to set
Name string `yaml:"name"`
// Value is the value of the header to set
Value string `yaml:"value"`
}
func (r *ResponseHeaderRule) GetOperation() HeaderRuleOperation {
return r.Operation
}
func (r *ResponseHeaderRule) GetMatching() string {
return r.Matching
}
type EngineDebugConfiguration struct {
PrintOperationTransformations bool `envDefault:"false" env:"ENGINE_DEBUG_PRINT_OPERATION_TRANSFORMATIONS" yaml:"print_operation_transformations"`
PrintOperationEnableASTRefs bool `envDefault:"false" env:"ENGINE_DEBUG_PRINT_OPERATION_ENABLE_AST_REFS" yaml:"print_operation_enable_ast_refs"`
PrintPlanningPaths bool `envDefault:"false" env:"ENGINE_DEBUG_PRINT_PLANNING_PATHS" yaml:"print_planning_paths"`
PrintQueryPlans bool `envDefault:"false" env:"ENGINE_DEBUG_PRINT_QUERY_PLANS" yaml:"print_query_plans"`
PrintIntermediateQueryPlans bool `envDefault:"false" env:"ENGINE_DEBUG_PRINT_INTERMEDIATE_QUERY_PLANS" yaml:"print_intermediate_query_plans"`
PrintNodeSuggestions bool `envDefault:"false" env:"ENGINE_DEBUG_PRINT_NODE_SUGGESTIONS" yaml:"print_node_suggestions"`
ConfigurationVisitor bool `envDefault:"false" env:"ENGINE_DEBUG_CONFIGURATION_VISITOR" yaml:"configuration_visitor"`
PlanningVisitor bool `envDefault:"false" env:"ENGINE_DEBUG_PLANNING_VISITOR" yaml:"planning_visitor"`
DatasourceVisitor bool `envDefault:"false" env:"ENGINE_DEBUG_DATASOURCE_VISITOR" yaml:"datasource_visitor"`
ReportWebSocketConnections bool `envDefault:"false" env:"ENGINE_DEBUG_REPORT_WEBSOCKET_CONNECTIONS" yaml:"report_websocket_connections"`
ReportMemoryUsage bool `envDefault:"false" env:"ENGINE_DEBUG_REPORT_MEMORY_USAGE" yaml:"report_memory_usage"`
EnableResolverDebugging bool `envDefault:"false" env:"ENGINE_DEBUG_ENABLE_RESOLVER_DEBUGGING" yaml:"enable_resolver_debugging"`
// EnablePersistedOperationsCacheResponseHeader is deprecated, use EnableCacheResponseHeaders instead.
EnablePersistedOperationsCacheResponseHeader bool `envDefault:"false" env:"ENGINE_DEBUG_ENABLE_PERSISTED_OPERATIONS_CACHE_RESPONSE_HEADER" yaml:"enable_persisted_operations_cache_response_header"`
// EnableNormalizationCacheResponseHeader is deprecated, use EnableCacheResponseHeaders instead.
EnableNormalizationCacheResponseHeader bool `envDefault:"false" env:"ENGINE_DEBUG_ENABLE_NORMALIZATION_CACHE_RESPONSE_HEADER" yaml:"enable_normalization_cache_response_header"`
EnableCacheResponseHeaders bool `envDefault:"false" env:"ENGINE_DEBUG_ENABLE_CACHE_RESPONSE_HEADERS" yaml:"enable_cache_response_headers"`
AlwaysIncludeQueryPlan bool `envDefault:"false" env:"ENGINE_DEBUG_ALWAYS_INCLUDE_QUERY_PLAN" yaml:"always_include_query_plan"`
AlwaysSkipLoader bool `envDefault:"false" env:"ENGINE_DEBUG_ALWAYS_SKIP_LOADER" yaml:"always_skip_loader"`
}
type EngineExecutionConfiguration struct {
Debug EngineDebugConfiguration `yaml:"debug"`
EnableSingleFlight bool `envDefault:"true" env:"ENGINE_ENABLE_SINGLE_FLIGHT" yaml:"enable_single_flight"`
// ForceEnableSingleFlight always enables single flight, except for mutations
// By default, SingleFlight / Request Deduplication is disabled when PreOriginHandlers are configured
// This is because PreOriginHandlers can modify request headers, which has influence on the request deduplication key
// If you're sure that your PreOriginHandlers won't interfere with the request deduplication key, you can enable it with this flag
ForceEnableSingleFlight bool `envDefault:"false" env:"ENGINE_FORCE_ENABLE_SINGLE_FLIGHT" yaml:"force_enable_single_flight"`
EnableInboundRequestDeduplication bool `envDefault:"true" env:"ENGINE_ENABLE_INBOUND_REQUEST_DEDUPLICATION" yaml:"enable_inbound_request_deduplication"`
// ForceEnableInboundRequestDeduplication forces enable inbound request deduplication, even when PreOriginHandlers are configured
ForceEnableInboundRequestDeduplication bool `envDefault:"false" env:"ENGINE_FORCE_ENABLE_INBOUND_REQUEST_DEDUPLICATION" yaml:"force_enable_inbound_request_deduplication"`
EnableRequestTracing bool `envDefault:"true" env:"ENGINE_ENABLE_REQUEST_TRACING" yaml:"enable_request_tracing"`
// ForceUnauthenticatedRequestTracing always enables request tracing for unauthenticated requests,
// even when Development Mode is not enabled. USE WITH CAUTION.
ForceUnauthenticatedRequestTracing bool `envDefault:"false" env:"ENGINE_FORCE_UNAUTHENTICATED_REQUEST_TRACING" yaml:"force_unauthenticated_request_tracing"`
// Deprecated: EnableExecutionPlanCacheResponseHeader is deprecated, use EngineDebugConfiguration.EnableCacheResponseHeaders instead.
EnableExecutionPlanCacheResponseHeader bool `envDefault:"false" env:"ENGINE_ENABLE_EXECUTION_PLAN_CACHE_RESPONSE_HEADER" yaml:"enable_execution_plan_cache_response_header"`
MaxConcurrentResolvers int `envDefault:"1024" env:"ENGINE_MAX_CONCURRENT_RESOLVERS" yaml:"max_concurrent_resolvers,omitempty"`
EnableNetPoll bool `envDefault:"true" env:"ENGINE_ENABLE_NET_POLL" yaml:"enable_net_poll"`
ExecutionPlanCacheSize int64 `envDefault:"1024" env:"ENGINE_EXECUTION_PLAN_CACHE_SIZE" yaml:"execution_plan_cache_size,omitempty"`
SlowPlanCacheSize int64 `envDefault:"300" env:"ENGINE_SLOW_PLAN_CACHE_SIZE" yaml:"slow_plan_cache_size,omitempty"`
SlowPlanCacheThreshold time.Duration `envDefault:"100ms" env:"ENGINE_SLOW_PLAN_CACHE_THRESHOLD" yaml:"slow_plan_cache_threshold,omitempty"`
MinifySubgraphOperations bool `envDefault:"true" env:"ENGINE_MINIFY_SUBGRAPH_OPERATIONS" yaml:"minify_subgraph_operations"`
EnablePersistedOperationsCache bool `envDefault:"true" env:"ENGINE_ENABLE_PERSISTED_OPERATIONS_CACHE" yaml:"enable_persisted_operations_cache"`
EnableNormalizationCache bool `envDefault:"true" env:"ENGINE_ENABLE_NORMALIZATION_CACHE" yaml:"enable_normalization_cache"`
NormalizationCacheSize int64 `envDefault:"1024" env:"ENGINE_NORMALIZATION_CACHE_SIZE" yaml:"normalization_cache_size,omitempty"`
OperationHashCacheSize int64 `envDefault:"2048" env:"ENGINE_OPERATION_HASH_CACHE_SIZE" yaml:"operation_hash_cache_size,omitempty"`
ParseKitPoolSize int `envDefault:"16" env:"ENGINE_PARSEKIT_POOL_SIZE" yaml:"parsekit_pool_size,omitempty"`
EnableValidationCache bool `envDefault:"true" env:"ENGINE_ENABLE_VALIDATION_CACHE" yaml:"enable_validation_cache"`
ValidationCacheSize int64 `envDefault:"1024" env:"ENGINE_VALIDATION_CACHE_SIZE" yaml:"validation_cache_size,omitempty"`
DisableExposingVariablesContentOnValidationError bool `envDefault:"false" env:"ENGINE_DISABLE_EXPOSING_VARIABLES_CONTENT_ON_VALIDATION_ERROR" yaml:"disable_exposing_variables_content_on_validation_error"`
ResolverMaxRecyclableParserSize int `envDefault:"32768" env:"ENGINE_RESOLVER_MAX_RECYCLABLE_PARSER_SIZE" yaml:"resolver_max_recyclable_parser_size,omitempty"`
EnableSubgraphFetchOperationName bool `envDefault:"false" env:"ENGINE_ENABLE_SUBGRAPH_FETCH_OPERATION_NAME" yaml:"enable_subgraph_fetch_operation_name"`
DisableVariablesRemapping bool `envDefault:"false" env:"ENGINE_DISABLE_VARIABLES_REMAPPING" yaml:"disable_variables_remapping"`
EnableRequireFetchReasons bool `envDefault:"false" env:"ENGINE_ENABLE_REQUIRE_FETCH_REASONS" yaml:"enable_require_fetch_reasons"`
SubscriptionFetchTimeout time.Duration `envDefault:"30s" env:"ENGINE_SUBSCRIPTION_FETCH_TIMEOUT" yaml:"subscription_fetch_timeout,omitempty"`
// Server-side WebSocket handler options (router accepting client connections)
WebSocketServerReadTimeout time.Duration `envDefault:"5s" env:"ENGINE_WEBSOCKET_SERVER_READ_TIMEOUT" yaml:"websocket_server_read_timeout,omitempty"`
WebSocketServerWriteTimeout time.Duration `envDefault:"10s" env:"ENGINE_WEBSOCKET_SERVER_WRITE_TIMEOUT" yaml:"websocket_server_write_timeout,omitempty"`
WebSocketServerPollTimeout time.Duration `envDefault:"1s" env:"ENGINE_WEBSOCKET_SERVER_POLL_TIMEOUT" yaml:"websocket_server_poll_timeout,omitempty"`
WebSocketServerConnBufferSize int `envDefault:"128" env:"ENGINE_WEBSOCKET_SERVER_CONN_BUFFER_SIZE" yaml:"websocket_server_conn_buffer_size,omitempty"`
// Subscription client options (router connecting to subgraphs)
WebSocketClientWriteTimeout time.Duration `envDefault:"10s" env:"ENGINE_WEBSOCKET_CLIENT_WRITE_TIMEOUT" yaml:"websocket_client_write_timeout,omitempty"`
WebSocketClientReadLimit BytesString `envDefault:"1MB" env:"ENGINE_WEBSOCKET_CLIENT_READ_LIMIT" yaml:"websocket_client_read_limit,omitempty"`
WebSocketClientPingInterval time.Duration `envDefault:"15s" env:"ENGINE_WEBSOCKET_CLIENT_PING_INTERVAL" yaml:"websocket_client_ping_interval,omitempty"`
WebSocketClientPingTimeout time.Duration `envDefault:"30s" env:"ENGINE_WEBSOCKET_CLIENT_PING_TIMEOUT" yaml:"websocket_client_ping_timeout,omitempty"`
WebSocketClientAckTimeout time.Duration `envDefault:"30s" env:"ENGINE_WEBSOCKET_CLIENT_ACK_TIMEOUT" yaml:"websocket_client_ack_timeout,omitempty"`
ValidateRequiredExternalFields bool `envDefault:"false" env:"ENGINE_VALIDATE_REQUIRED_EXTERNAL_FIELDS" yaml:"validate_required_external_fields"`
RelaxSubgraphOperationFieldSelectionMergingNullability bool `envDefault:"false" env:"ENGINE_RELAX_SUBGRAPH_OPERATION_FIELD_SELECTION_MERGING_NULLABILITY" yaml:"relax_subgraph_operation_field_selection_merging_nullability"`
}
type BlockOperationConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"ENABLED"`
Condition string `yaml:"condition" env:"CONDITION"`
}
type SecurityConfiguration struct {
BlockMutations BlockOperationConfiguration `yaml:"block_mutations" envPrefix:"SECURITY_BLOCK_MUTATIONS_"`
BlockSubscriptions BlockOperationConfiguration `yaml:"block_subscriptions" envPrefix:"SECURITY_BLOCK_SUBSCRIPTIONS_"`
BlockNonPersistedOperations BlockOperationConfiguration `yaml:"block_non_persisted_operations" envPrefix:"SECURITY_BLOCK_NON_PERSISTED_OPERATIONS_"`
BlockPersistedOperations BlockOperationConfiguration `yaml:"block_persisted_operations" envPrefix:"SECURITY_BLOCK_PERSISTED_OPERATIONS_"`
ComplexityCalculationCache *ComplexityCalculationCache `yaml:"complexity_calculation_cache"`
ComplexityLimits *ComplexityLimits `yaml:"complexity_limits"`
CostControl *CostControl `yaml:"cost_control" envPrefix:"SECURITY_COST_CONTROL_"`
DepthLimit *QueryDepthConfiguration `yaml:"depth_limit"`
ParserLimits ParserLimitsConfiguration `yaml:"parser_limits"`
OperationNameLengthLimit int `yaml:"operation_name_length_limit" envDefault:"512" env:"SECURITY_OPERATION_NAME_LENGTH_LIMIT"` // 0 is disabled
}
type ParserLimitsConfiguration struct {
ApproximateDepthLimit int `yaml:"approximate_depth_limit,omitempty" envDefault:"200"` // 0 means disabled
TotalFieldsLimit int `yaml:"total_fields_limit,omitempty" envDefault:"3500"` // 0 means disabled
}
type QueryDepthConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"SECURITY_QUERY_DEPTH_ENABLED"`
Limit int `yaml:"limit,omitempty" envDefault:"0" env:"SECURITY_QUERY_DEPTH_LIMIT"`
CacheSize int64 `yaml:"cache_size,omitempty" envDefault:"1024" env:"SECURITY_QUERY_DEPTH_CACHE_SIZE"`
IgnorePersistedOperations bool `yaml:"ignore_persisted_operations,omitempty" envDefault:"false" env:"SECURITY_QUERY_DEPTH_IGNORE_PERSISTED_OPERATIONS"`
}
type ComplexityCalculationCache struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"SECURITY_COMPLEXITY_CACHE_ENABLED"`
CacheSize int64 `yaml:"size,omitempty" envDefault:"1024" env:"SECURITY_COMPLEXITY_CACHE_SIZE"`
}
// ComplexityLimitsMode defines how complexity limits behave.
type ComplexityLimitsMode string
const (
ComplexityLimitsModeUnset ComplexityLimitsMode = ""
ComplexityLimitsModeMeasure ComplexityLimitsMode = "measure"
ComplexityLimitsModeEnforce ComplexityLimitsMode = "enforce"
)
type ComplexityLimits struct {
// Mode controls complexity limits behavior:
// - "measure": calculates complexity without rejecting operations (for monitoring)
// - "enforce": calculates complexity and rejects operations exceeding limits
Mode ComplexityLimitsMode `yaml:"mode,omitempty"`
Depth *ComplexityLimit `yaml:"depth"`
TotalFields *ComplexityLimit `yaml:"total_fields"`
RootFields *ComplexityLimit `yaml:"root_fields"`
RootFieldAliases *ComplexityLimit `yaml:"root_field_aliases"`
// When set to true, complexity validation is ignored for all introspection queries.
IgnoreIntrospection bool `yaml:"ignore_introspection" envDefault:"false" env:"SECURITY_COMPLEXITY_IGNORE_INTROSPECTION"`
}
// CostControlMode defines how cost control behaves.
type CostControlMode string
const (
CostControlModeMeasure CostControlMode = "measure"
CostControlModeEnforce CostControlMode = "enforce"
)
// CostControl configures cost control based on @cost and @listSize directives.
type CostControl struct {
// Enabled controls whether cost control is active.
// When true, the router calculates costs for every operation.
Enabled bool `yaml:"enabled" envDefault:"false" env:"ENABLED"`
// Mode controls cost control behavior:
// - "measure": calculates costs without rejecting operations (for monitoring)
// - "enforce": calculates costs and rejects operations exceeding the estimated limit
Mode CostControlMode `yaml:"mode,omitempty" envDefault:"measure" env:"MODE"`
// MaxEstimatedLimit is the maximum allowed estimated cost for a query.
// Requires Mode set to "enforce". Operations exceeding this limit are rejected.
MaxEstimatedLimit int `yaml:"max_estimated_limit,omitempty" env:"MAX_ESTIMATED_LIMIT"`
// EstimatedListSize is the default assumed size for list fields when no @listSize directive
// nor slicing argument is provided. Used as a multiplier for estimated cost calculation.
EstimatedListSize int `yaml:"estimated_list_size,omitempty" env:"ESTIMATED_LIST_SIZE"`
// ExposeHeaders adds X-WG-Cost-* response headers.
ExposeHeaders bool `yaml:"expose_headers,omitempty" envDefault:"false" env:"EXPOSE_HEADERS"`
}
type ComplexityLimit struct {
Enabled bool `yaml:"enabled" envDefault:"false"`
Limit int `yaml:"limit,omitempty" envDefault:"0"`
IgnorePersistedOperations bool `yaml:"ignore_persisted_operations,omitempty" envDefault:"false"`
}
func (c *ComplexityLimit) ApplyLimit(isPersistent bool) bool {
return c.Enabled && (!isPersistent || !c.IgnorePersistedOperations)
}
type OverrideRoutingURLConfiguration struct {
Subgraphs map[string]string `yaml:"subgraphs"`
}
type SubgraphOverridesConfiguration struct {
RoutingURL string `yaml:"routing_url"`
SubscriptionURL string `yaml:"subscription_url"`
SubscriptionProtocol string `yaml:"subscription_protocol"`
SubscriptionWebsocketSubprotocol string `yaml:"subscription_websocket_subprotocol"`
}
type OverridesConfiguration struct {
Subgraphs map[string]SubgraphOverridesConfiguration `yaml:"subgraphs"`
}
type JWKSConfiguration struct {
URL string `yaml:"url"`
AllowedUse []string `yaml:"allowed_use"`
Algorithms []string `yaml:"algorithms"`
RefreshInterval time.Duration `yaml:"refresh_interval" envDefault:"1m"`
RefreshUnknownKID RefreshUnknownKID `yaml:"refresh_unknown_kid"`
// For secret based where we need to create a jwk entry with
// a key id and algorithm
Secret string `yaml:"secret"`
Algorithm string `yaml:"symmetric_algorithm"`
KeyId string `yaml:"header_key_id"`
// Common
Audiences []string `yaml:"audiences"`
}
type RefreshUnknownKID struct {
Enabled bool `yaml:"enabled" envDefault:"false"`
MaxWait time.Duration `yaml:"max_wait" envDefault:"2m"`
Interval time.Duration `yaml:"interval" envDefault:"30s"`
Burst int `yaml:"burst" envDefault:"2"`
}
type HeaderSource struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
ValuePrefixes []string `yaml:"value_prefixes"`
}
type JWTAuthenticationConfiguration struct {
JWKS []JWKSConfiguration `yaml:"jwks"`
ScopeClaim string `yaml:"scope_claim" envDefault:"scope"`
HeaderName string `yaml:"header_name" envDefault:"Authorization"`
HeaderValuePrefix string `yaml:"header_value_prefix" envDefault:"Bearer"`
HeaderSources []HeaderSource `yaml:"header_sources"`
}
type AuthenticationConfiguration struct {
JWT JWTAuthenticationConfiguration `yaml:"jwt"`
IgnoreIntrospection bool `yaml:"ignore_introspection" envDefault:"false"`
}
type AuthorizationConfiguration struct {
RequireAuthentication bool `yaml:"require_authentication" envDefault:"false" env:"REQUIRE_AUTHENTICATION"`
// RejectOperationIfUnauthorized makes the router reject the whole GraphQL Operation if one field fails to authorize
RejectOperationIfUnauthorized bool `yaml:"reject_operation_if_unauthorized" envDefault:"false" env:"REJECT_OPERATION_IF_UNAUTHORIZED"`
}
type RateLimitConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"RATE_LIMIT_ENABLED"`
Strategy string `yaml:"strategy" envDefault:"simple" env:"RATE_LIMIT_STRATEGY"`
SimpleStrategy RateLimitSimpleStrategy `yaml:"simple_strategy"`
Storage RedisConfiguration `yaml:"storage"`
// Debug ensures that retryAfter and resetAfter are set to stable values for testing
// Debug also exposes the rate limit key in the response extension for debugging purposes
Debug bool `yaml:"debug" envDefault:"false" env:"RATE_LIMIT_DEBUG"`
KeySuffixExpression string `yaml:"key_suffix_expression,omitempty" env:"RATE_LIMIT_KEY_SUFFIX_EXPRESSION"`
ErrorExtensionCode RateLimitErrorExtensionCode `yaml:"error_extension_code"`
}
type RateLimitErrorExtensionCode struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"RATE_LIMIT_ERROR_EXTENSION_CODE_ENABLED"`
Code string `yaml:"code" envDefault:"RATE_LIMIT_EXCEEDED" env:"RATE_LIMIT_ERROR_EXTENSION_CODE"`
}
type RedisConfiguration struct {
URLs []string `yaml:"urls,omitempty" env:"RATE_LIMIT_REDIS_URLS"`
ClusterEnabled bool `yaml:"cluster_enabled,omitempty" envDefault:"false" env:"RATE_LIMIT_REDIS_CLUSTER_ENABLED"`
KeyPrefix string `yaml:"key_prefix,omitempty" envDefault:"cosmo_rate_limit" env:"RATE_LIMIT_REDIS_KEY_PREFIX"`
}
type RateLimitSimpleStrategy struct {
Rate int `yaml:"rate" envDefault:"10" env:"RATE_LIMIT_SIMPLE_RATE"`
Burst int `yaml:"burst" envDefault:"10" env:"RATE_LIMIT_SIMPLE_BURST"`
Period time.Duration `yaml:"period" envDefault:"1s" env:"RATE_LIMIT_SIMPLE_PERIOD"`
RejectExceedingRequests bool `yaml:"reject_exceeding_requests" envDefault:"false" env:"RATE_LIMIT_SIMPLE_REJECT_EXCEEDING_REQUESTS"`
RejectStatusCode int `yaml:"reject_status_code" envDefault:"200" env:"RATE_LIMIT_SIMPLE_REJECT_STATUS_CODE"`
HideStatsFromResponseExtension bool `yaml:"hide_stats_from_response_extension" envDefault:"false" env:"RATE_LIMIT_SIMPLE_HIDE_STATS_FROM_RESPONSE_EXTENSION"`
Overrides []RateLimitOverride `yaml:"overrides,omitempty"`
}
type RateLimitOverride struct {
Matching string `yaml:"matching"`
Rate int `yaml:"rate"`
Burst int `yaml:"burst"`
Period time.Duration `yaml:"period"`
}
type CDNConfiguration struct {
URL string `yaml:"url" env:"CDN_URL" envDefault:"https://cosmo-cdn.wundergraph.com"`
CacheSize BytesString `yaml:"cache_size,omitempty" env:"CDN_CACHE_SIZE" envDefault:"100MB"`
}
type NatsTokenBasedAuthentication struct {
Token *string `yaml:"token,omitempty"`
}
type NatsCredentialsAuthentication struct {
Password *string `yaml:"password,omitempty"`
Username *string `yaml:"username,omitempty"`
}
type NatsAuthentication struct {
UserInfo NatsCredentialsAuthentication `yaml:"user_info"`
NatsTokenBasedAuthentication `yaml:"token,inline"`
}
type NatsTLSConfiguration struct {
InsecureSkipCaVerification bool `yaml:"insecure_skip_ca_verification,omitempty"`
CaFile string `yaml:"ca_file,omitempty"`
CertFile string `yaml:"cert_file,omitempty"`
KeyFile string `yaml:"key_file,omitempty"`
}
type NatsEventSource struct {
ID string `yaml:"id,omitempty"`
URL string `yaml:"url,omitempty"`
Authentication *NatsAuthentication `yaml:"authentication,omitempty"`
TLS *NatsTLSConfiguration `yaml:"tls,omitempty"`
DeleteDurableConsumersOnShutdown bool `yaml:"experiment_delete_durable_consumers_on_shutdown"`
}
func (n NatsEventSource) GetID() string {
return n.ID
}
type KafkaSASLPlainAuthentication struct {
Password *string `yaml:"password,omitempty"`
Username *string `yaml:"username,omitempty"`
}
func (k KafkaSASLPlainAuthentication) IsSet() bool {
return k.Username != nil && k.Password != nil
}
type KafkaSASLSCRAMMechanism string
const (
KafkaSASLSCRAMMechanismSCRAM256 KafkaSASLSCRAMMechanism = "SCRAM-SHA-256"
KafkaSASLSCRAMMechanismSCRAM512 KafkaSASLSCRAMMechanism = "SCRAM-SHA-512"
)
type KafkaSASLSCRAMAuthentication struct {
Password *string `yaml:"password,omitempty"`
Username *string `yaml:"username,omitempty"`
Mechanism *KafkaSASLSCRAMMechanism `yaml:"mechanism,omitempty"`
}
func (k KafkaSASLSCRAMAuthentication) IsSet() bool {
return k.Username != nil && k.Password != nil && k.Mechanism != nil
}
type KafkaAuthentication struct {
SASLPlain KafkaSASLPlainAuthentication `yaml:"sasl_plain,omitempty"`
SASLSCRAM KafkaSASLSCRAMAuthentication `yaml:"sasl_scram,omitempty"`
}
type KafkaTLSConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"false"`
}
type KafkaEventSource struct {
ID string `yaml:"id,omitempty"`
Brokers []string `yaml:"brokers,omitempty"`
Authentication *KafkaAuthentication `yaml:"authentication,omitempty"`
TLS *KafkaTLSConfiguration `yaml:"tls,omitempty"`
FetchMaxWait time.Duration `yaml:"fetch_max_wait,omitempty"`
}
func (k KafkaEventSource) GetID() string {
return k.ID
}
type RedisEventSource struct {
ID string `yaml:"id,omitempty"`
URLs []string `yaml:"urls,omitempty"`
ClusterEnabled bool `yaml:"cluster_enabled"`
}
func (r RedisEventSource) GetID() string {
return r.ID
}
type EventProviders struct {
Nats []NatsEventSource `yaml:"nats,omitempty"`
Kafka []KafkaEventSource `yaml:"kafka,omitempty"`
Redis []RedisEventSource `yaml:"redis,omitempty"`
}
type EventsConfiguration struct {
Providers EventProviders `yaml:"providers,omitempty"`
Handlers StreamsHandlerConfiguration `yaml:"handlers,omitempty"`
}
type StreamsHandlerConfiguration struct {
OnReceiveEvents OnReceiveEventsConfiguration `yaml:"on_receive_events"`
}
type OnReceiveEventsConfiguration struct {
MaxConcurrentHandlers int `yaml:"max_concurrent_handlers" envDefault:"100"`
HandlerTimeout time.Duration `yaml:"handler_timeout" envDefault:"5s"`
}
type Cluster struct {
Name string `yaml:"name,omitempty" env:"CLUSTER_NAME"`
}
type AbsintheProtocolConfiguration struct {
// Enabled true if the Router should accept Requests over WebSockets using the Absinthe Protocol (Phoenix) Handler
Enabled bool `yaml:"enabled" envDefault:"true" env:"WEBSOCKETS_ABSINTHE_ENABLED"`
// HandlerPath is the path where the Absinthe Protocol Handler is mounted
// On this specific path, the Router will accept WebSocket Requests using the Absinthe Protocol
// even if the Sub-protocol is not set to "absinthe"
// Legacy clients might not set the Sub-protocol Header, so this is a fallback
HandlerPath string `yaml:"handler_path" envDefault:"/absinthe/socket" env:"WEBSOCKETS_ABSINTHE_HANDLER_PATH"`
}
type ComplianceConfig struct {
AnonymizeIP AnonymizeIpConfiguration `yaml:"anonymize_ip,omitempty"`
}
type ExportTokenConfiguration struct {
// Enabled true if the Router should export the token to the client request header
Enabled bool `yaml:"enabled" envDefault:"true"`
// HeaderKey is the name of the header where the token should be exported to
HeaderKey string `yaml:"header_key,omitempty" envDefault:"Authorization"`
}
type WebSocketAuthenticationConfiguration struct {
// Tells if the Router should look for the JWT Token in the initial payload of the WebSocket Connection
FromInitialPayload InitialPayloadAuthenticationConfiguration `yaml:"from_initial_payload,omitempty"`
}
type InitialPayloadAuthenticationConfiguration struct {
// When true the Router should look for the token in the initial payload of the WebSocket Connection
Enabled bool `yaml:"enabled,omitempty" envDefault:"false"`
// The key in the initial payload where the token is stored
Key string `yaml:"key,omitempty" envDefault:"Authorization"`
// ExportToken represents the configuration for exporting the token to the client request header.
ExportToken ExportTokenConfiguration `yaml:"export_token"`
}
type WebSocketConfiguration struct {
// Enabled true if the Router should accept Requests over WebSockets
Enabled bool `yaml:"enabled" envDefault:"true" env:"WEBSOCKETS_ENABLED"`
// AbsintheProtocol configuration for the Absinthe Protocol
AbsintheProtocol AbsintheProtocolConfiguration `yaml:"absinthe_protocol,omitempty"`
// ForwardUpgradeHeaders true if the Router should forward Upgrade Request Headers in the Extensions payload when starting a Subscription on a Subgraph
ForwardUpgradeHeaders ForwardUpgradeHeadersConfiguration `yaml:"forward_upgrade_headers"`
// ForwardUpgradeQueryParamsInExtensions true if the Router should forward Upgrade Request Query Parameters in the Extensions payload when starting a Subscription on a Subgraph
ForwardUpgradeQueryParams ForwardUpgradeQueryParamsConfiguration `yaml:"forward_upgrade_query_params"`
// ForwardInitialPayload true if the Router should forward the initial payload of a Subscription Request to the Subgraph
ForwardInitialPayload bool `yaml:"forward_initial_payload" envDefault:"true" env:"WEBSOCKETS_FORWARD_INITIAL_PAYLOAD"`
// Authentication configuration for the WebSocket Connection
Authentication WebSocketAuthenticationConfiguration `yaml:"authentication,omitempty"`
// SetClientInfoFromInitialPayload configuration for the WebSocket Connection
ClientInfoFromInitialPayload WebSocketClientInfoFromInitialPayloadConfiguration `yaml:"client_info_from_initial_payload"`
}
type WebSocketClientInfoFromInitialPayloadConfiguration struct {
// Enabled true if the Router should set the client info from the initial payload of a Subscription Request to the Subgraph
Enabled bool `yaml:"enabled" envDefault:"true" env:"WEBSOCKETS_CLIENT_INFO_FROM_INITIAL_PAYLOAD_ENABLED"`
// NameField is the name of the field in the initial payload that will have the client name
NameField string `yaml:"name_field" envDefault:"graphql-client-name" env:"WEBSOCKETS_CLIENT_INFO_FROM_INITIAL_PAYLOAD_NAME_FIELD"`
// VersionField is the name of the field in the initial payload that will have the client version
VersionField string `yaml:"version_field" envDefault:"graphql-client-version" env:"WEBSOCKETS_CLIENT_INFO_FROM_INITIAL_PAYLOAD_VERSION_FIELD"`
// ForwardToRequestHeaders configuration for the WebSocket Connection
ForwardToRequestHeaders ForwardToRequestHeadersConfiguration `yaml:"forward_to_request_headers"`
}
type ForwardToRequestHeadersConfiguration struct {
// Enabled true if the Router should forward the client info to the request headers
Enabled bool `yaml:"enabled" envDefault:"true" env:"WEBSOCKETS_CLIENT_INFO_FROM_INITIAL_PAYLOAD_FORWARD_TO_REQUEST_HEADERS_ENABLED"`
// NameTargetHeader is the name of the header where the client name should be forwarded to
NameTargetHeader string `yaml:"name_target_header" envDefault:"graphql-client-name" env:"WEBSOCKETS_CLIENT_INFO_FROM_INITIAL_PAYLOAD_NAME_TARGET_HEADER"`
// VersionTargetHeader is the name of the header where the client version should be forwarded to
VersionTargetHeader string `yaml:"version_target_header" envDefault:"graphql-client-version" env:"WEBSOCKETS_CLIENT_INFO_FROM_INITIAL_PAYLOAD_VERSION_TARGET_HEADER"`
}
type ForwardUpgradeHeadersConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"FORWARD_UPGRADE_HEADERS_ENABLED"`
AllowList []string `yaml:"allow_list" envDefault:"Authorization" env:"FORWARD_UPGRADE_HEADERS_ALLOW_LIST"`
}
type ForwardUpgradeQueryParamsConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"FORWARD_UPGRADE_QUERY_PARAMS_ENABLED"`
AllowList []string `yaml:"allow_list" envDefault:"Authorization" env:"FORWARD_UPGRADE_QUERY_PARAMS_ALLOW_LIST"`
}
type AnonymizeIpConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"SECURITY_ANONYMIZE_IP_ENABLED"`
Method string `yaml:"method" envDefault:"redact" env:"SECURITY_ANONYMIZE_IP_METHOD"`
}
type TLSClientAuthConfiguration struct {
CertFile string `yaml:"cert_file,omitempty" env:"TLS_CLIENT_AUTH_CERT_FILE"`
Required bool `yaml:"required" envDefault:"false" env:"TLS_CLIENT_AUTH_REQUIRED"`
}
type TLSServerConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"TLS_SERVER_ENABLED"`
CertFile string `yaml:"cert_file,omitempty" env:"TLS_SERVER_CERT_FILE"`
KeyFile string `yaml:"key_file,omitempty" env:"TLS_SERVER_KEY_FILE"`
ClientAuth TLSClientAuthConfiguration `yaml:"client_auth,omitempty"`
}
type TLSClientCertConfiguration struct {
CertFile string `yaml:"cert_file,omitempty" env:"CERT_FILE"`
KeyFile string `yaml:"key_file,omitempty" env:"KEY_FILE"`
CaFile string `yaml:"ca_file,omitempty" env:"CA_FILE"`
InsecureSkipCaVerification bool `yaml:"insecure_skip_ca_verification" envDefault:"false" env:"INSECURE_SKIP_CA_VERIFICATION"`
}
type ClientTLSConfiguration struct {
// All applies to all subgraph connections.
All TLSClientCertConfiguration `yaml:"all" envPrefix:"TLS_CLIENT_ALL_"`
// Subgraphs overrides per-subgraph TLS config. Key is the subgraph name.
Subgraphs map[string]TLSClientCertConfiguration `yaml:"subgraphs,omitempty"`
}
type TLSConfiguration struct {
Server TLSServerConfiguration `yaml:"server"`
Client ClientTLSConfiguration `yaml:"client"`
}
type SubgraphErrorPropagationMode string
const (
SubgraphErrorPropagationModeWrapped SubgraphErrorPropagationMode = "wrapped"
SubgraphErrorPropagationModePassthrough SubgraphErrorPropagationMode = "pass-through"
)
type SubgraphErrorPropagationConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"true" env:"ENABLED"`
PropagateStatusCodes bool `yaml:"propagate_status_codes" envDefault:"false" env:"STATUS_CODES"`
Mode SubgraphErrorPropagationMode `yaml:"mode" envDefault:"wrapped" env:"MODE"`
RewritePaths bool `yaml:"rewrite_paths" envDefault:"true" env:"REWRITE_PATHS"`
OmitLocations bool `yaml:"omit_locations" envDefault:"true" env:"OMIT_LOCATIONS"`
OmitExtensions bool `yaml:"omit_extensions" envDefault:"false" env:"OMIT_EXTENSIONS"`
AttachServiceName bool `yaml:"attach_service_name" envDefault:"true" env:"ATTACH_SERVICE_NAME"`
DefaultExtensionCode string `yaml:"default_extension_code" envDefault:"DOWNSTREAM_SERVICE_ERROR" env:"DEFAULT_EXTENSION_CODE"`
AllowAllExtensionFields bool `yaml:"allow_all_extension_fields" envDefault:"false" env:"ALLOW_ALL_EXTENSION_FIELDS"`
AllowedExtensionFields []string `yaml:"allowed_extension_fields" envDefault:"code" env:"ALLOWED_EXTENSION_FIELDS"`
AllowedFields []string `yaml:"allowed_fields" env:"ALLOWED_FIELDS"`
}
type SubgraphExtensionPropagationAlgorithm string
const (
// SubgraphExtensionPropagationAlgorithmFirstWrite propagates the first extension root field from a subgraph to the client
SubgraphExtensionPropagationAlgorithmFirstWrite SubgraphExtensionPropagationAlgorithm = "first_write"
// SubgraphExtensionPropagationAlgorithmLastWrite propagates the last extension root field from a subgraph to the client
SubgraphExtensionPropagationAlgorithmLastWrite SubgraphExtensionPropagationAlgorithm = "last_write"
)
type SubgraphExtensionPropagationConfiguration struct {
Enabled bool `yaml:"enabled" envDefault:"false" env:"ENABLED"`
AllowedExtensionFields []string `yaml:"allowed_extension_fields" env:"ALLOWED_EXTENSION_FIELDS"`
Algorithm SubgraphExtensionPropagationAlgorithm `yaml:"algorithm,omitempty" envDefault:"first_write" env:"ALGORITHM"`
}
type StorageProviders struct {
S3 []S3StorageProvider `yaml:"s3,omitempty" envPrefix:"S3_"`
CDN []CDNStorageProvider `yaml:"cdn,omitempty" envPrefix:"CDN_"`
Redis []RedisStorageProvider `yaml:"redis,omitempty" envPrefix:"REDIS_"`
FileSystem []FileSystemStorageProvider `yaml:"file_system,omitempty" envPrefix:"FS_"`
}
type PersistedOperationsStorageConfig struct {
ProviderID string `yaml:"provider_id,omitempty" env:"PERSISTED_OPERATIONS_STORAGE_PROVIDER_ID"`
ObjectPrefix string `yaml:"object_prefix,omitempty" env:"PERSISTED_OPERATIONS_STORAGE_OBJECT_PREFIX"`
}
type AutomaticPersistedQueriesStorageConfig struct {
ProviderID string `yaml:"provider_id,omitempty" env:"APQ_STORAGE_PROVIDER_ID"`
ObjectPrefix string `yaml:"object_prefix,omitempty" env:"APQ_STORAGE_OBJECT_PREFIX"`
}
type S3StorageProvider struct {
ID string `yaml:"id,omitempty" env:"ID"`
Endpoint string `yaml:"endpoint,omitempty" env:"ENDPOINT"`
AccessKey string `yaml:"access_key,omitempty" env:"ACCESS_KEY"`
SecretKey string `yaml:"secret_key,omitempty" env:"SECRET_KEY"`
Bucket string `yaml:"bucket,omitempty" env:"BUCKET"`
Region string `yaml:"region,omitempty" env:"REGION"`
Secure bool `yaml:"secure,omitempty" env:"SECURE"`
}
type CDNStorageProvider struct {
ID string `yaml:"id,omitempty" env:"ID"`
URL string `yaml:"url,omitempty" env:"URL" envDefault:"https://cosmo-cdn.wundergraph.com"`
}
type FileSystemStorageProvider struct {
ID string `yaml:"id,omitempty" env:"ID"`
Path string `yaml:"path,omitempty" env:"PATH"`
}
type RedisStorageProvider struct {
ID string `yaml:"id,omitempty" env:"ID"`
URLs []string `yaml:"urls,omitempty" env:"URLS"`
ClusterEnabled bool `yaml:"cluster_enabled,omitempty" env:"CLUSTER_ENABLED" envDefault:"false"`
}
type PersistedOperationsCDNProvider struct {
URL string `yaml:"url,omitempty" envDefault:"https://cosmo-cdn.wundergraph.com"`
}
type ExecutionConfigStorage struct {
ProviderID string `yaml:"provider_id,omitempty" env:"PROVIDER_ID"`