async_graphql_poem/
query.rs

1use std::time::Duration;
2
3use async_graphql::{
4    Executor,
5    http::{create_multipart_mixed_stream, is_accept_multipart_mixed},
6};
7use futures_util::StreamExt;
8use poem::{Body, Endpoint, FromRequest, IntoResponse, Request, Response, Result};
9
10use crate::{GraphQLBatchRequest, GraphQLBatchResponse, GraphQLRequest};
11
12/// A GraphQL query endpoint.
13///
14/// # Example
15///
16/// ```
17/// use async_graphql::{EmptyMutation, EmptySubscription, Object, Schema};
18/// use async_graphql_poem::GraphQL;
19/// use poem::{Route, post};
20///
21/// struct Query;
22///
23/// #[Object]
24/// impl Query {
25///     async fn value(&self) -> i32 {
26///         100
27///     }
28/// }
29///
30/// type MySchema = Schema<Query, EmptyMutation, EmptySubscription>;
31///
32/// let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
33/// let app = Route::new().at("/", post(GraphQL::new(schema)));
34/// ```
35pub struct GraphQL<E> {
36    executor: E,
37}
38
39impl<E> GraphQL<E> {
40    /// Create a GraphQL endpoint.
41    pub fn new(executor: E) -> Self {
42        Self { executor }
43    }
44}
45
46impl<E> Endpoint for GraphQL<E>
47where
48    E: Executor,
49{
50    type Output = Response;
51
52    async fn call(&self, req: Request) -> Result<Self::Output> {
53        let is_accept_multipart_mixed = req
54            .header("accept")
55            .map(is_accept_multipart_mixed)
56            .unwrap_or_default();
57
58        if is_accept_multipart_mixed {
59            let (req, mut body) = req.split();
60            let req = GraphQLRequest::from_request(&req, &mut body).await?;
61            let stream = self.executor.execute_stream(req.0, None);
62            Ok(Response::builder()
63                .header("content-type", "multipart/mixed; boundary=graphql")
64                .body(Body::from_bytes_stream(
65                    create_multipart_mixed_stream(stream, Duration::from_secs(30))
66                        .map(Ok::<_, std::io::Error>),
67                )))
68        } else {
69            let (req, mut body) = req.split();
70            let req = GraphQLBatchRequest::from_request(&req, &mut body).await?;
71            Ok(GraphQLBatchResponse(self.executor.execute_batch(req.0).await).into_response())
72        }
73    }
74}