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
use std::time::Duration;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::config::primitives::{
file_path::FilePath, retry_policy::RetryPolicyConfig, single_or_multiple::SingleOrMultiple,
value_or_expression::ValueOrExpression,
};
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields, tag = "source")]
pub enum SupergraphSource {
/// Loads a supergraph from the filesystem.
/// The path can be either absolute or relative to the router's working directory.
#[serde(rename = "file")]
File {
/// The path to the supergraph file.
///
/// Can also be set using the `SUPERGRAPH_FILE_PATH` environment variable.
path: Option<FilePath>,
/// Optional interval at which the file should be polled for changes.
/// If not provided, the file will only be loaded once when the router starts.
#[serde(
default = "default_file_poll_interval",
deserialize_with = "humantime_serde::deserialize",
serialize_with = "humantime_serde::serialize"
)]
#[schemars(with = "String")]
poll_interval: Option<Duration>,
},
/// Loads a supergraph from Hive Console CDN.
#[serde(rename = "hive")]
HiveConsole {
/// The CDN endpoint from Hive Console target.
///
/// Can also be set using the `HIVE_CDN_ENDPOINT` environment variable.
endpoint: Option<SingleOrMultiple<String>>,
/// The CDN Access Token with from the Hive Console target.
///
/// Can also be set using the `HIVE_CDN_KEY` environment variable.
key: Option<String>,
/// Interval at which the Hive Console should be polled for changes.
///
/// Can also be set using the `HIVE_CDN_POLL_INTERVAL` environment variable.
#[serde(
default = "default_hive_poll_interval",
deserialize_with = "humantime_serde::deserialize",
serialize_with = "humantime_serde::serialize"
)]
#[schemars(with = "String")]
poll_interval: Duration,
/// Request timeout for the Hive Console CDN requests.
#[serde(
default = "default_hive_request_timeout",
deserialize_with = "humantime_serde::deserialize",
serialize_with = "humantime_serde::serialize"
)]
#[schemars(with = "String")]
request_timeout: Duration,
/// Connect timeout for the Hive Console CDN requests.
#[serde(
default = "default_hive_connect_timeout",
deserialize_with = "humantime_serde::deserialize",
serialize_with = "humantime_serde::serialize"
)]
#[schemars(with = "String")]
connect_timeout: Duration,
/// Whether to accept invalid TLS certificates when connecting to the Hive Console CDN.
#[serde(default = "default_accept_invalid_certs")]
accept_invalid_certs: bool,
/// Interval at which the Hive Console should be polled for changes.
///
/// By default, an exponential backoff retry policy is used, with 10 attempts.
#[serde(default = "default_hive_retry_policy")]
retry_policy: RetryPolicyConfig,
},
/// Loads a supergraph from Apollo GraphOS Uplink.
#[serde(rename = "apollo_graphos")]
ApolloGraphOS {
/// The graph ref of the managed federation graph (`<GRAPH_ID>@<VARIANT>`).
///
/// Can also be set using the `APOLLO_GRAPH_REF` environment variable.
graph_ref: Option<String>,
/// The Apollo API key, with at least the `service:read` permission.
///
/// Can also be set using the `APOLLO_KEY` environment variable.
key: Option<String>,
/// The Apollo Uplink endpoint(s) to poll, tried in order on each poll.
///
/// Can also be set using the `APOLLO_UPLINK_ENDPOINTS` environment variable
/// (comma-separated).
#[serde(default = "default_apollo_uplink_endpoints")]
endpoint: SingleOrMultiple<String>,
/// The timeout for a single HTTP call to Apollo Uplink.
#[serde(
default = "default_apollo_uplink_timeout",
deserialize_with = "humantime_serde::deserialize",
serialize_with = "humantime_serde::serialize"
)]
#[schemars(with = "String")]
timeout: Duration,
/// Whether to accept invalid TLS certificates when connecting to Apollo Uplink.
#[serde(default = "default_accept_invalid_certs")]
accept_invalid_certs: bool,
},
#[serde(rename = "storage")]
Storage {
/// The storage id as it was defined in the config file, under `storages:` field.
storage_id: String,
/// The path to the supergraph file in the storage/bucket.
location: ValueOrExpression<String>,
/// Optional interval at which the file should be polled for changes.
/// If not provided, the file will only be loaded once when the router starts.
#[serde(
default = "default_file_poll_interval",
deserialize_with = "humantime_serde::deserialize",
serialize_with = "humantime_serde::serialize"
)]
#[schemars(with = "String")]
poll_interval: Option<Duration>,
},
/// No configured supergraph source. A plugin must select a supergraph for every GraphQL
/// request and WebSocket upgrade that needs one, via `set_supergraph` in
/// `on_http_request`.
///
/// There is deliberately no fallback: if no plugin supplies one, the request fails with
/// the same `NO_SUPERGRAPH_AVAILABLE` response the router uses while a configured supergraph
/// hasn't loaded yet.
#[serde(rename = "plugin")]
Plugin,
}
fn default_accept_invalid_certs() -> bool {
false
}
fn default_hive_request_timeout() -> Duration {
Duration::from_secs(60)
}
fn default_hive_connect_timeout() -> Duration {
Duration::from_secs(10)
}
fn default_hive_retry_policy() -> RetryPolicyConfig {
RetryPolicyConfig { max_retries: 10 }
}
/// Apollo's managed federation Uplink endpoints: GCP first, AWS as fallback.
/// Matches the default order used by Apollo Router itself.
fn default_apollo_uplink_endpoints() -> SingleOrMultiple<String> {
SingleOrMultiple::Multiple(vec![
"https://uplink.api.apollographql.com/".to_string(),
"https://aws.uplink.api.apollographql.com/".to_string(),
])
}
fn default_apollo_uplink_timeout() -> Duration {
Duration::from_secs(30)
}
impl SupergraphSource {
pub fn source_name(&self) -> &str {
match self {
SupergraphSource::File { .. } => "file",
SupergraphSource::HiveConsole { .. } => "hive",
SupergraphSource::ApolloGraphOS { .. } => "apollo_graphos",
SupergraphSource::Storage { storage_id, .. } => storage_id.as_str(),
SupergraphSource::Plugin => "plugin",
}
}
}
fn default_hive_poll_interval() -> Duration {
Duration::from_secs(10)
}
fn default_file_poll_interval() -> Option<Duration> {
None
}
impl Default for SupergraphSource {
fn default() -> Self {
SupergraphSource::File {
path: FilePath::new_from_relative("supergraph.graphql").ok(),
poll_interval: default_file_poll_interval(),
}
}
}