Upgrade juniper_hyper
to 1.0 hyper
(#1217)
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kai Ren <tyranron@gmail.com>
This commit is contained in:
parent
9f776fd0a1
commit
813c0d1210
4 changed files with 137 additions and 105 deletions
|
@ -11,10 +11,12 @@ All user visible changes to `juniper_hyper` crate will be documented in this fil
|
||||||
### BC Breaks
|
### BC Breaks
|
||||||
|
|
||||||
- Switched to 0.16 version of [`juniper` crate].
|
- Switched to 0.16 version of [`juniper` crate].
|
||||||
|
- Switched to 1 version of [`hyper` crate]. ([#1217])
|
||||||
- Changed return type of all functions from `Response<Body>` to `Response<String>`. ([#1101], [#1096])
|
- Changed return type of all functions from `Response<Body>` to `Response<String>`. ([#1101], [#1096])
|
||||||
|
|
||||||
[#1096]: /../../issues/1096
|
[#1096]: /../../issues/1096
|
||||||
[#1101]: /../../pull/1101
|
[#1101]: /../../pull/1101
|
||||||
|
[#1217]: /../../pull/1217
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,4 +29,5 @@ See [old CHANGELOG](/../../blob/juniper_hyper-v0.8.0/juniper_hyper/CHANGELOG.md)
|
||||||
|
|
||||||
|
|
||||||
[`juniper` crate]: https://docs.rs/juniper
|
[`juniper` crate]: https://docs.rs/juniper
|
||||||
|
[`hyper` crate]: https://docs.rs/hyper
|
||||||
[Semantic Versioning 2.0.0]: https://semver.org
|
[Semantic Versioning 2.0.0]: https://semver.org
|
||||||
|
|
|
@ -16,18 +16,18 @@ exclude = ["/examples/", "/release.toml"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.22"
|
futures = "0.3.22"
|
||||||
hyper = { version = "0.14.7", features = ["server", "runtime"] }
|
http-body-util = "0.1"
|
||||||
|
hyper = { version = "1.0", features = ["server"] }
|
||||||
juniper = { version = "0.16.0-dev", path = "../juniper", default-features = false }
|
juniper = { version = "0.16.0-dev", path = "../juniper", default-features = false }
|
||||||
serde_json = "1.0.18"
|
serde_json = "1.0.18"
|
||||||
tokio = "1.0"
|
tokio = "1.0"
|
||||||
url = "2.0"
|
url = "2.0"
|
||||||
|
|
||||||
# Fixes for `minimal-versions` check.
|
|
||||||
# TODO: Try remove on upgrade of `hyper` crate.
|
|
||||||
http-body = "0.4.5"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
hyper = { version = "1.0", features = ["http1"] }
|
||||||
|
hyper-util = { version = "0.1", features = ["tokio"] }
|
||||||
juniper = { version = "0.16.0-dev", path = "../juniper", features = ["expose-test-schema"] }
|
juniper = { version = "0.16.0-dev", path = "../juniper", features = ["expose-test-schema"] }
|
||||||
|
log = "0.4"
|
||||||
pretty_env_logger = "0.5"
|
pretty_env_logger = "0.5"
|
||||||
reqwest = { version = "0.11", features = ["blocking", "rustls-tls"], default-features = false }
|
reqwest = { version = "0.11", features = ["blocking", "rustls-tls"], default-features = false }
|
||||||
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.0", features = ["macros", "net", "rt-multi-thread"] }
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
use std::{convert::Infallible, sync::Arc};
|
use std::{convert::Infallible, env, error::Error, net::SocketAddr, sync::Arc};
|
||||||
|
|
||||||
use hyper::{
|
use hyper::{server::conn::http1, service::service_fn, Method, Response, StatusCode};
|
||||||
server::Server,
|
use hyper_util::rt::TokioIo;
|
||||||
service::{make_service_fn, service_fn},
|
|
||||||
Method, Response, StatusCode,
|
|
||||||
};
|
|
||||||
use juniper::{
|
use juniper::{
|
||||||
tests::fixtures::starwars::schema::{Database, Query},
|
tests::fixtures::starwars::schema::{Database, Query},
|
||||||
EmptyMutation, EmptySubscription, RootNode,
|
EmptyMutation, EmptySubscription, RootNode,
|
||||||
};
|
};
|
||||||
|
use juniper_hyper::{graphiql, graphql, playground};
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
|
env::set_var("RUST_LOG", "info");
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
let addr = ([127, 0, 0, 1], 3000).into();
|
|
||||||
|
|
||||||
let db = Arc::new(Database::new());
|
let db = Arc::new(Database::new());
|
||||||
let root_node = Arc::new(RootNode::new(
|
let root_node = Arc::new(RootNode::new(
|
||||||
Query,
|
Query,
|
||||||
|
@ -23,35 +21,46 @@ async fn main() {
|
||||||
EmptySubscription::<Database>::new(),
|
EmptySubscription::<Database>::new(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let new_service = make_service_fn(move |_| {
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
let root_node = root_node.clone();
|
let listener = TcpListener::bind(addr).await?;
|
||||||
let ctx = db.clone();
|
log::info!("Listening on http://{addr}");
|
||||||
|
loop {
|
||||||
|
let (stream, _) = listener.accept().await?;
|
||||||
|
let io = TokioIo::new(stream);
|
||||||
|
|
||||||
async {
|
|
||||||
Ok::<_, hyper::Error>(service_fn(move |req| {
|
|
||||||
let root_node = root_node.clone();
|
let root_node = root_node.clone();
|
||||||
let ctx = ctx.clone();
|
let db = db.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let root_node = root_node.clone();
|
||||||
|
let db = db.clone();
|
||||||
|
|
||||||
|
if let Err(e) = http1::Builder::new()
|
||||||
|
.serve_connection(
|
||||||
|
io,
|
||||||
|
service_fn(move |req| {
|
||||||
|
let root_node = root_node.clone();
|
||||||
|
let db = db.clone();
|
||||||
async {
|
async {
|
||||||
Ok::<_, Infallible>(match (req.method(), req.uri().path()) {
|
Ok::<_, Infallible>(match (req.method(), req.uri().path()) {
|
||||||
(&Method::GET, "/") => juniper_hyper::graphiql("/graphql", None).await,
|
|
||||||
(&Method::GET, "/graphql") | (&Method::POST, "/graphql") => {
|
(&Method::GET, "/graphql") | (&Method::POST, "/graphql") => {
|
||||||
juniper_hyper::graphql(root_node, ctx, req).await
|
graphql(root_node, db, req).await
|
||||||
}
|
}
|
||||||
|
(&Method::GET, "/graphiql") => graphiql("/graphql", None).await,
|
||||||
|
(&Method::GET, "/playground") => playground("/graphql", None).await,
|
||||||
_ => {
|
_ => {
|
||||||
let mut response = Response::new(String::new());
|
let mut resp = Response::new(String::new());
|
||||||
*response.status_mut() = StatusCode::NOT_FOUND;
|
*resp.status_mut() = StatusCode::NOT_FOUND;
|
||||||
response
|
resp
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}))
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log::error!("Error serving connection: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let server = Server::bind(&addr).serve(new_service);
|
|
||||||
println!("Listening on http://{addr}");
|
|
||||||
|
|
||||||
if let Err(e) = server.await {
|
|
||||||
eprintln!("server error: {e}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
use std::{error::Error, fmt, string::FromUtf8Error, sync::Arc};
|
use std::{error::Error, fmt, string::FromUtf8Error, sync::Arc};
|
||||||
|
|
||||||
|
use http_body_util::BodyExt as _;
|
||||||
use hyper::{
|
use hyper::{
|
||||||
|
body,
|
||||||
header::{self, HeaderValue},
|
header::{self, HeaderValue},
|
||||||
Body, Method, Request, Response, StatusCode,
|
Method, Request, Response, StatusCode,
|
||||||
};
|
};
|
||||||
use juniper::{
|
use juniper::{
|
||||||
http::{GraphQLBatchRequest, GraphQLRequest as JuniperGraphQLRequest, GraphQLRequest},
|
http::{GraphQLBatchRequest, GraphQLRequest as JuniperGraphQLRequest, GraphQLRequest},
|
||||||
|
@ -16,7 +18,7 @@ use url::form_urlencoded;
|
||||||
pub async fn graphql_sync<CtxT, QueryT, MutationT, SubscriptionT, S>(
|
pub async fn graphql_sync<CtxT, QueryT, MutationT, SubscriptionT, S>(
|
||||||
root_node: Arc<RootNode<'static, QueryT, MutationT, SubscriptionT, S>>,
|
root_node: Arc<RootNode<'static, QueryT, MutationT, SubscriptionT, S>>,
|
||||||
context: Arc<CtxT>,
|
context: Arc<CtxT>,
|
||||||
req: Request<Body>,
|
req: Request<body::Incoming>,
|
||||||
) -> Response<String>
|
) -> Response<String>
|
||||||
where
|
where
|
||||||
QueryT: GraphQLType<S, Context = CtxT>,
|
QueryT: GraphQLType<S, Context = CtxT>,
|
||||||
|
@ -37,7 +39,7 @@ where
|
||||||
pub async fn graphql<CtxT, QueryT, MutationT, SubscriptionT, S>(
|
pub async fn graphql<CtxT, QueryT, MutationT, SubscriptionT, S>(
|
||||||
root_node: Arc<RootNode<'static, QueryT, MutationT, SubscriptionT, S>>,
|
root_node: Arc<RootNode<'static, QueryT, MutationT, SubscriptionT, S>>,
|
||||||
context: Arc<CtxT>,
|
context: Arc<CtxT>,
|
||||||
req: Request<Body>,
|
req: Request<body::Incoming>,
|
||||||
) -> Response<String>
|
) -> Response<String>
|
||||||
where
|
where
|
||||||
QueryT: GraphQLTypeAsync<S, Context = CtxT>,
|
QueryT: GraphQLTypeAsync<S, Context = CtxT>,
|
||||||
|
@ -56,7 +58,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn parse_req<S: ScalarValue>(
|
async fn parse_req<S: ScalarValue>(
|
||||||
req: Request<Body>,
|
req: Request<body::Incoming>,
|
||||||
) -> Result<GraphQLBatchRequest<S>, Response<String>> {
|
) -> Result<GraphQLBatchRequest<S>, Response<String>> {
|
||||||
match *req.method() {
|
match *req.method() {
|
||||||
Method::GET => parse_get_req(req),
|
Method::GET => parse_get_req(req),
|
||||||
|
@ -77,7 +79,7 @@ async fn parse_req<S: ScalarValue>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_get_req<S: ScalarValue>(
|
fn parse_get_req<S: ScalarValue>(
|
||||||
req: Request<Body>,
|
req: Request<body::Incoming>,
|
||||||
) -> Result<GraphQLBatchRequest<S>, GraphQLRequestError> {
|
) -> Result<GraphQLBatchRequest<S>, GraphQLRequestError> {
|
||||||
req.uri()
|
req.uri()
|
||||||
.query()
|
.query()
|
||||||
|
@ -90,13 +92,14 @@ fn parse_get_req<S: ScalarValue>(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn parse_post_json_req<S: ScalarValue>(
|
async fn parse_post_json_req<S: ScalarValue>(
|
||||||
body: Body,
|
body: body::Incoming,
|
||||||
) -> Result<GraphQLBatchRequest<S>, GraphQLRequestError> {
|
) -> Result<GraphQLBatchRequest<S>, GraphQLRequestError> {
|
||||||
let chunk = hyper::body::to_bytes(body)
|
let chunk = body
|
||||||
|
.collect()
|
||||||
.await
|
.await
|
||||||
.map_err(GraphQLRequestError::BodyHyper)?;
|
.map_err(GraphQLRequestError::BodyHyper)?;
|
||||||
|
|
||||||
let input = String::from_utf8(chunk.iter().cloned().collect())
|
let input = String::from_utf8(chunk.to_bytes().iter().cloned().collect())
|
||||||
.map_err(GraphQLRequestError::BodyUtf8)?;
|
.map_err(GraphQLRequestError::BodyUtf8)?;
|
||||||
|
|
||||||
serde_json::from_str::<GraphQLBatchRequest<S>>(&input)
|
serde_json::from_str::<GraphQLBatchRequest<S>>(&input)
|
||||||
|
@ -104,13 +107,14 @@ async fn parse_post_json_req<S: ScalarValue>(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn parse_post_graphql_req<S: ScalarValue>(
|
async fn parse_post_graphql_req<S: ScalarValue>(
|
||||||
body: Body,
|
body: body::Incoming,
|
||||||
) -> Result<GraphQLBatchRequest<S>, GraphQLRequestError> {
|
) -> Result<GraphQLBatchRequest<S>, GraphQLRequestError> {
|
||||||
let chunk = hyper::body::to_bytes(body)
|
let chunk = body
|
||||||
|
.collect()
|
||||||
.await
|
.await
|
||||||
.map_err(GraphQLRequestError::BodyHyper)?;
|
.map_err(GraphQLRequestError::BodyHyper)?;
|
||||||
|
|
||||||
let query = String::from_utf8(chunk.iter().cloned().collect())
|
let query = String::from_utf8(chunk.to_bytes().iter().cloned().collect())
|
||||||
.map_err(GraphQLRequestError::BodyUtf8)?;
|
.map_err(GraphQLRequestError::BodyUtf8)?;
|
||||||
|
|
||||||
Ok(GraphQLBatchRequest::Single(GraphQLRequest::new(
|
Ok(GraphQLBatchRequest::Single(GraphQLRequest::new(
|
||||||
|
@ -306,18 +310,19 @@ impl Error for GraphQLRequestError {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use hyper::{
|
use std::{
|
||||||
server::Server,
|
convert::Infallible, error::Error, net::SocketAddr, panic, sync::Arc, time::Duration,
|
||||||
service::{make_service_fn, service_fn},
|
|
||||||
Method, Response, StatusCode,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use hyper::{server::conn::http1, service::service_fn, Method, Response, StatusCode};
|
||||||
|
use hyper_util::rt::TokioIo;
|
||||||
use juniper::{
|
use juniper::{
|
||||||
http::tests as http_tests,
|
http::tests as http_tests,
|
||||||
tests::fixtures::starwars::schema::{Database, Query},
|
tests::fixtures::starwars::schema::{Database, Query},
|
||||||
EmptyMutation, EmptySubscription, RootNode,
|
EmptyMutation, EmptySubscription, RootNode,
|
||||||
};
|
};
|
||||||
use reqwest::{self, blocking::Response as ReqwestResponse};
|
use reqwest::blocking::Response as ReqwestResponse;
|
||||||
use std::{convert::Infallible, net::SocketAddr, sync::Arc, thread, time::Duration};
|
use tokio::{net::TcpListener, task, time::sleep};
|
||||||
|
|
||||||
struct TestHyperIntegration {
|
struct TestHyperIntegration {
|
||||||
port: u16,
|
port: u16,
|
||||||
|
@ -373,7 +378,7 @@ mod tests {
|
||||||
|
|
||||||
async fn run_hyper_integration(is_sync: bool) {
|
async fn run_hyper_integration(is_sync: bool) {
|
||||||
let port = if is_sync { 3002 } else { 3001 };
|
let port = if is_sync { 3002 } else { 3001 };
|
||||||
let addr: SocketAddr = ([127, 0, 0, 1], port).into();
|
let addr = SocketAddr::from(([127, 0, 0, 1], port));
|
||||||
|
|
||||||
let db = Arc::new(Database::new());
|
let db = Arc::new(Database::new());
|
||||||
let root_node = Arc::new(RootNode::new(
|
let root_node = Arc::new(RootNode::new(
|
||||||
|
@ -382,14 +387,27 @@ mod tests {
|
||||||
EmptySubscription::<Database>::new(),
|
EmptySubscription::<Database>::new(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let new_service = make_service_fn(move |_| {
|
let server: task::JoinHandle<Result<(), Box<dyn Error + Send + Sync>>> =
|
||||||
let root_node = root_node.clone();
|
task::spawn(async move {
|
||||||
let ctx = db.clone();
|
let listener = TcpListener::bind(addr).await?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (stream, _) = listener.accept().await?;
|
||||||
|
let io = TokioIo::new(stream);
|
||||||
|
|
||||||
async move {
|
|
||||||
Ok::<_, hyper::Error>(service_fn(move |req| {
|
|
||||||
let root_node = root_node.clone();
|
let root_node = root_node.clone();
|
||||||
let ctx = ctx.clone();
|
let db = db.clone();
|
||||||
|
|
||||||
|
_ = task::spawn(async move {
|
||||||
|
let root_node = root_node.clone();
|
||||||
|
let db = db.clone();
|
||||||
|
|
||||||
|
if let Err(e) = http1::Builder::new()
|
||||||
|
.serve_connection(
|
||||||
|
io,
|
||||||
|
service_fn(move |req| {
|
||||||
|
let root_node = root_node.clone();
|
||||||
|
let db = db.clone();
|
||||||
let matches = {
|
let matches = {
|
||||||
let path = req.uri().path();
|
let path = req.uri().path();
|
||||||
match req.method() {
|
match req.method() {
|
||||||
|
@ -402,9 +420,9 @@ mod tests {
|
||||||
async move {
|
async move {
|
||||||
Ok::<_, Infallible>(if matches {
|
Ok::<_, Infallible>(if matches {
|
||||||
if is_sync {
|
if is_sync {
|
||||||
super::graphql_sync(root_node, ctx, req).await
|
super::graphql_sync(root_node, db, req).await
|
||||||
} else {
|
} else {
|
||||||
super::graphql(root_node, ctx, req).await
|
super::graphql(root_node, db, req).await
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut resp = Response::new(String::new());
|
let mut resp = Response::new(String::new());
|
||||||
|
@ -412,29 +430,31 @@ mod tests {
|
||||||
resp
|
resp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}))
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
eprintln!("server error: {e}");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let (shutdown_fut, shutdown) = futures::future::abortable(async {
|
sleep(Duration::from_secs(10)).await; // wait 10ms for `server` to bind
|
||||||
tokio::time::sleep(Duration::from_secs(60)).await;
|
|
||||||
});
|
|
||||||
|
|
||||||
let server = Server::bind(&addr)
|
match task::spawn_blocking(move || {
|
||||||
.serve(new_service)
|
|
||||||
.with_graceful_shutdown(async {
|
|
||||||
shutdown_fut.await.unwrap_err();
|
|
||||||
});
|
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
|
||||||
thread::sleep(Duration::from_millis(10)); // wait 10ms for server to bind
|
|
||||||
let integration = TestHyperIntegration { port };
|
let integration = TestHyperIntegration { port };
|
||||||
http_tests::run_http_test_suite(&integration);
|
http_tests::run_http_test_suite(&integration);
|
||||||
shutdown.abort();
|
})
|
||||||
});
|
.await
|
||||||
|
{
|
||||||
|
Err(f) if f.is_panic() => panic::resume_unwind(f.into_panic()),
|
||||||
|
Ok(()) | Err(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(e) = server.await {
|
server.abort();
|
||||||
eprintln!("server error: {e}");
|
if let Ok(Err(e)) = server.await {
|
||||||
|
panic!("server failed: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue