async_graphql/http/
mod.rs1#[cfg(feature = "altair")]
4mod altair_source;
5#[cfg(feature = "graphiql")]
6mod graphiql_plugin;
7#[cfg(feature = "graphiql")]
8mod graphiql_source;
9#[cfg(feature = "graphiql")]
10mod graphiql_v2_source;
11mod multipart;
12mod multipart_subscribe;
13#[cfg(feature = "playground")]
14mod playground_source;
15mod websocket;
16
17use std::io::ErrorKind;
18
19#[cfg(feature = "altair")]
20pub use altair_source::*;
21use futures_util::io::{AsyncRead, AsyncReadExt};
22#[cfg(feature = "graphiql")]
23pub use graphiql_plugin::{graphiql_plugin_explorer, GraphiQLPlugin};
24#[cfg(feature = "graphiql")]
25pub use graphiql_source::graphiql_source;
26#[cfg(feature = "graphiql")]
27pub use graphiql_v2_source::{Credentials, GraphiQLSource};
28pub use multipart::MultipartOptions;
29pub use multipart_subscribe::{create_multipart_mixed_stream, is_accept_multipart_mixed};
30#[cfg(feature = "playground")]
31pub use playground_source::{playground_source, GraphQLPlaygroundConfig};
32use serde::Deserialize;
33pub use websocket::{
34 default_on_connection_init, default_on_ping, ClientMessage, DefaultOnConnInitType,
35 DefaultOnPingType, Protocols as WebSocketProtocols, WebSocket, WsMessage,
36 ALL_WEBSOCKET_PROTOCOLS,
37};
38
39use crate::{BatchRequest, ParseRequestError, Request};
40
41pub fn parse_query_string(input: &str) -> Result<Request, ParseRequestError> {
43 #[derive(Deserialize)]
44 struct RequestSerde {
45 #[serde(default)]
46 pub query: String,
47 pub operation_name: Option<String>,
48 pub variables: Option<String>,
49 pub extensions: Option<String>,
50 }
51
52 let request: RequestSerde = serde_urlencoded::from_str(input)
53 .map_err(|err| std::io::Error::new(ErrorKind::Other, err))?;
54 let variables = request
55 .variables
56 .map(|data| serde_json::from_str(&data))
57 .transpose()
58 .map_err(|err| {
59 std::io::Error::new(ErrorKind::Other, format!("invalid variables: {}", err))
60 })?
61 .unwrap_or_default();
62 let extensions = request
63 .extensions
64 .map(|data| serde_json::from_str(&data))
65 .transpose()
66 .map_err(|err| {
67 std::io::Error::new(ErrorKind::Other, format!("invalid extensions: {}", err))
68 })?
69 .unwrap_or_default();
70
71 Ok(Request {
72 operation_name: request.operation_name,
73 variables,
74 extensions,
75 ..Request::new(request.query)
76 })
77}
78
79pub async fn receive_body(
81 content_type: Option<impl AsRef<str>>,
82 body: impl AsyncRead + Send,
83 opts: MultipartOptions,
84) -> Result<Request, ParseRequestError> {
85 receive_batch_body(content_type, body, opts)
86 .await?
87 .into_single()
88}
89
90pub async fn receive_batch_body(
92 content_type: Option<impl AsRef<str>>,
93 body: impl AsyncRead + Send,
94 opts: MultipartOptions,
95) -> Result<BatchRequest, ParseRequestError> {
96 let content_type = content_type
98 .as_ref()
99 .map(AsRef::as_ref)
100 .unwrap_or("application/json");
101
102 let content_type: mime::Mime = content_type.parse()?;
103
104 match (content_type.type_(), content_type.subtype()) {
105 (mime::MULTIPART, _) => {
107 if let Some(boundary) = content_type.get_param("boundary") {
108 multipart::receive_batch_multipart(body, boundary.to_string(), opts).await
109 } else {
110 Err(ParseRequestError::InvalidMultipart(
111 multer::Error::NoBoundary,
112 ))
113 }
114 }
115 _ => receive_batch_body_no_multipart(&content_type, body).await,
120 }
121}
122
123pub(super) async fn receive_batch_body_no_multipart(
127 content_type: &mime::Mime,
128 body: impl AsyncRead + Send,
129) -> Result<BatchRequest, ParseRequestError> {
130 assert_ne!(content_type.type_(), mime::MULTIPART, "received multipart");
131 match (content_type.type_(), content_type.subtype()) {
132 #[cfg(feature = "cbor")]
133 (mime::OCTET_STREAM, _) | (mime::APPLICATION, mime::OCTET_STREAM) => {
136 receive_batch_cbor(body).await
137 }
138 _ => receive_batch_json(body).await,
140 }
141}
142pub async fn receive_json(body: impl AsyncRead) -> Result<Request, ParseRequestError> {
144 receive_batch_json(body).await?.into_single()
145}
146
147pub async fn receive_batch_json(body: impl AsyncRead) -> Result<BatchRequest, ParseRequestError> {
149 let mut data = Vec::new();
150 futures_util::pin_mut!(body);
151 body.read_to_end(&mut data)
152 .await
153 .map_err(ParseRequestError::Io)?;
154 serde_json::from_slice::<BatchRequest>(&data)
155 .map_err(|e| ParseRequestError::InvalidRequest(Box::new(e)))
156}
157
158#[cfg(feature = "cbor")]
160#[cfg_attr(docsrs, doc(cfg(feature = "cbor")))]
161pub async fn receive_cbor(body: impl AsyncRead) -> Result<Request, ParseRequestError> {
162 receive_batch_cbor(body).await?.into_single()
163}
164
165#[cfg(feature = "cbor")]
167#[cfg_attr(docsrs, doc(cfg(feature = "cbor")))]
168pub async fn receive_batch_cbor(body: impl AsyncRead) -> Result<BatchRequest, ParseRequestError> {
169 let mut data = Vec::new();
170 futures_util::pin_mut!(body);
171 body.read_to_end(&mut data)
172 .await
173 .map_err(ParseRequestError::Io)?;
174 serde_cbor::from_slice::<BatchRequest>(&data)
175 .map_err(|e| ParseRequestError::InvalidRequest(Box::new(e)))
176}
177
178#[cfg(test)]
179mod tests {
180 use std::collections::HashMap;
181
182 use async_graphql_value::Extensions;
183
184 use super::*;
185 use crate::{value, Variables};
186
187 #[test]
188 fn test_parse_query_string() {
189 let request = parse_query_string("variables=%7B%7D&extensions=%7B%22persistedQuery%22%3A%7B%22sha256Hash%22%3A%22cde5de0a350a19c59f8ddcd9646e5f260b2a7d5649ff6be8e63e9462934542c3%22%2C%22version%22%3A1%7D%7D").unwrap();
190 assert_eq!(request.query.as_str(), "");
191 assert_eq!(request.variables, Variables::default());
192 assert_eq!(request.extensions, {
193 let mut extensions = HashMap::new();
194 extensions.insert("persistedQuery".to_string(), value!({
195 "sha256Hash": "cde5de0a350a19c59f8ddcd9646e5f260b2a7d5649ff6be8e63e9462934542c3",
196 "version": 1,
197 }));
198 Extensions(extensions)
199 });
200
201 let request = parse_query_string("query={a}&variables=%7B%22a%22%3A10%7D").unwrap();
202 assert_eq!(request.query.as_str(), "{a}");
203 assert_eq!(
204 request.variables,
205 Variables::from_value(value!({ "a" : 10 }))
206 );
207 }
208}