-
Notifications
You must be signed in to change notification settings - Fork 245
/
override_url.rs
141 lines (125 loc) 路 4.4 KB
/
override_url.rs
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
//! Allows subgraph URLs to be overridden.
use std::collections::HashMap;
use std::str::FromStr;
use http::Uri;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use tower::BoxError;
use tower::ServiceExt;
use crate::plugin::Plugin;
use crate::plugin::PluginInit;
use crate::register_plugin;
use crate::services::subgraph;
use crate::services::SubgraphRequest;
#[derive(Debug, Clone)]
struct OverrideSubgraphUrl {
urls: HashMap<String, Uri>,
}
/// Subgraph URL mappings
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
#[serde(untagged)]
enum Conf {
/// Subgraph URL mappings
Mapping(HashMap<String, String>),
}
#[async_trait::async_trait]
impl Plugin for OverrideSubgraphUrl {
type Config = Conf;
async fn new(init: PluginInit<Self::Config>) -> Result<Self, BoxError> {
let Conf::Mapping(urls) = init.config;
Ok(OverrideSubgraphUrl {
urls: urls
.into_iter()
.map(|(k, url)| {
#[cfg(unix)]
// there is no standard for unix socket URLs apparently
if let Some(path) = url.strip_prefix("unix://") {
// there is no specified format for unix socket URLs (cf https://github.com/whatwg/url/issues/577)
// so a unix:// URL will not be parsed by http::Uri
// To fix that, hyperlocal came up with its own Uri type that can be converted to http::Uri.
// It hides the socket path in a hex encoded authority that the unix socket connector will
// know how to decode
Ok((k, hyperlocal::Uri::new(path, "/").into()))
} else {
Uri::from_str(&url).map(|url| (k, url))
}
#[cfg(not(unix))]
Uri::from_str(&url).map(|url| (k, url))
})
.collect::<Result<_, _>>()?,
})
}
fn subgraph_service(
&self,
subgraph_name: &str,
service: subgraph::BoxService,
) -> subgraph::BoxService {
let new_url = self.urls.get(subgraph_name).cloned();
service
.map_request(move |mut req: SubgraphRequest| {
if let Some(new_url) = new_url.clone() {
*req.subgraph_request.uri_mut() = new_url;
}
req
})
.boxed()
}
}
register_plugin!("apollo", "override_subgraph_url", OverrideSubgraphUrl);
#[cfg(test)]
mod tests {
use std::str::FromStr;
use http::Uri;
use serde_json::Value;
use tower::util::BoxService;
use tower::Service;
use tower::ServiceExt;
use crate::plugin::test::MockSubgraphService;
use crate::plugin::DynPlugin;
use crate::services::SubgraphRequest;
use crate::services::SubgraphResponse;
use crate::Context;
#[tokio::test]
async fn plugin_registered() {
let mut mock_service = MockSubgraphService::new();
mock_service
.expect_call()
.withf(|req| {
req.subgraph_request.uri() == &Uri::from_str("http://localhost:8001").unwrap()
})
.times(1)
.returning(move |req: SubgraphRequest| {
Ok(SubgraphResponse::fake_builder()
.context(req.context)
.build())
});
let dyn_plugin: Box<dyn DynPlugin> = crate::plugin::plugins()
.find(|factory| factory.name == "apollo.override_subgraph_url")
.expect("Plugin not found")
.create_instance_without_schema(
&Value::from_str(
r#"{
"test_one": "http://localhost:8001",
"test_two": "http://localhost:8002"
}"#,
)
.unwrap(),
)
.await
.unwrap();
let mut subgraph_service =
dyn_plugin.subgraph_service("test_one", BoxService::new(mock_service));
let context = Context::new();
context.insert("test".to_string(), 5i64).unwrap();
let subgraph_req = SubgraphRequest::fake_builder().context(context);
let _subgraph_resp = subgraph_service
.ready()
.await
.unwrap()
.call(subgraph_req.build())
.await
.unwrap();
}
}