async_graphql_actix_web/
handler.rs1use std::time::Duration;
2
3use actix_http::StatusCode;
4use actix_web::{Handler, HttpRequest, HttpResponse, Responder};
5use async_graphql::{
6 Executor,
7 http::{create_multipart_mixed_stream, is_accept_multipart_mixed},
8};
9use futures_util::{FutureExt, StreamExt, future::LocalBoxFuture};
10
11use crate::{GraphQLRequest, GraphQLResponse};
12
13#[derive(Clone)]
15pub struct GraphQL<E> {
16 executor: E,
17}
18
19impl<E> GraphQL<E> {
20 pub fn new(executor: E) -> Self {
22 Self { executor }
23 }
24}
25
26impl<E: Executor> Handler<(HttpRequest, GraphQLRequest)> for GraphQL<E> {
27 type Output = HttpResponse;
28 type Future = LocalBoxFuture<'static, Self::Output>;
29
30 fn call(&self, (http_req, graphql_req): (HttpRequest, GraphQLRequest)) -> Self::Future {
31 let executor = self.executor.clone();
32 async move {
33 let is_accept_multipart_mixed = http_req
34 .headers()
35 .get("accept")
36 .and_then(|value| value.to_str().ok())
37 .map(is_accept_multipart_mixed)
38 .unwrap_or_default();
39
40 if is_accept_multipart_mixed {
41 let stream = executor.execute_stream(graphql_req.0, None);
42 HttpResponse::build(StatusCode::OK)
43 .insert_header(("content-type", "multipart/mixed; boundary=graphql"))
44 .streaming(
45 create_multipart_mixed_stream(stream, Duration::from_secs(30))
46 .map(Ok::<_, actix_web::Error>),
47 )
48 } else {
49 GraphQLResponse(executor.execute(graphql_req.into_inner()).await.into())
50 .respond_to(&http_req)
51 }
52 }
53 .boxed_local()
54 }
55}