async-graphql-tide 2.0
This commit is contained in:
parent
394f45252f
commit
a0b55a9e43
@ -5,16 +5,13 @@
|
|||||||
#![allow(clippy::needless_doctest_main)]
|
#![allow(clippy::needless_doctest_main)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
use async_graphql::http::{GQLRequest, GQLResponse};
|
use async_graphql::http::{GQLRequest, MultipartOptions};
|
||||||
use async_graphql::{
|
use async_graphql::{ObjectType, Schema, SubscriptionType};
|
||||||
IntoQueryBuilder, ObjectType, QueryBuilder, ReceiveMultipartOptions, Response, Schema,
|
|
||||||
SubscriptionType,
|
|
||||||
};
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tide::{
|
use tide::{
|
||||||
http::{headers, Method},
|
http::{headers, Method},
|
||||||
Body, Request, Response, Status, StatusCode,
|
Body, Request, Response, StatusCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// GraphQL request handler
|
/// GraphQL request handler
|
||||||
@ -53,38 +50,34 @@ use tide::{
|
|||||||
pub async fn graphql<Query, Mutation, Subscription, TideState, F>(
|
pub async fn graphql<Query, Mutation, Subscription, TideState, F>(
|
||||||
req: Request<TideState>,
|
req: Request<TideState>,
|
||||||
schema: Schema<Query, Mutation, Subscription>,
|
schema: Schema<Query, Mutation, Subscription>,
|
||||||
query_builder_configuration: F,
|
configuration: F,
|
||||||
) -> tide::Result<Response>
|
) -> tide::Result<Response>
|
||||||
where
|
where
|
||||||
Query: ObjectType + Send + Sync + 'static,
|
Query: ObjectType + Send + Sync + 'static,
|
||||||
Mutation: ObjectType + Send + Sync + 'static,
|
Mutation: ObjectType + Send + Sync + 'static,
|
||||||
Subscription: SubscriptionType + Send + Sync + 'static,
|
Subscription: SubscriptionType + Send + Sync + 'static,
|
||||||
TideState: Clone + Send + Sync + 'static,
|
TideState: Clone + Send + Sync + 'static,
|
||||||
F: FnOnce(QueryBuilder) -> QueryBuilder + Send,
|
F: FnOnce(async_graphql::Request) -> async_graphql::Request + Send,
|
||||||
{
|
{
|
||||||
graphql_opts(req, schema, query_builder_configuration, Default::default()).await
|
graphql_opts(req, schema, configuration, Default::default()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Similar to graphql, but you can set the options `IntoQueryBuilderOpts`.
|
/// Similar to graphql, but you can set the options `MultipartOptions`.
|
||||||
pub async fn graphql_opts<Query, Mutation, Subscription, TideState, F>(
|
pub async fn graphql_opts<Query, Mutation, Subscription, TideState, F>(
|
||||||
req: Request<TideState>,
|
req: Request<TideState>,
|
||||||
schema: Schema<Query, Mutation, Subscription>,
|
schema: Schema<Query, Mutation, Subscription>,
|
||||||
query_builder_configuration: F,
|
configuration: F,
|
||||||
opts: ReceiveMultipartOptions,
|
opts: MultipartOptions,
|
||||||
) -> tide::Result<Response>
|
) -> tide::Result<Response>
|
||||||
where
|
where
|
||||||
Query: ObjectType + Send + Sync + 'static,
|
Query: ObjectType + Send + Sync + 'static,
|
||||||
Mutation: ObjectType + Send + Sync + 'static,
|
Mutation: ObjectType + Send + Sync + 'static,
|
||||||
Subscription: SubscriptionType + Send + Sync + 'static,
|
Subscription: SubscriptionType + Send + Sync + 'static,
|
||||||
TideState: Clone + Send + Sync + 'static,
|
TideState: Clone + Send + Sync + 'static,
|
||||||
F: FnOnce(QueryBuilder) -> QueryBuilder + Send,
|
F: FnOnce(async_graphql::Request) -> async_graphql::Request + Send,
|
||||||
{
|
{
|
||||||
let query_builder = req.body_graphql_opts(opts).await?;
|
let request = req.body_graphql_opts(opts).await?;
|
||||||
Response::new(StatusCode::Ok).body_graphql(
|
Response::new(StatusCode::Ok).body_graphql(schema.execute(configuration(request)).await)
|
||||||
query_builder_configuration(query_builder)
|
|
||||||
.execute(&schema)
|
|
||||||
.await,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tide request extension
|
/// Tide request extension
|
||||||
@ -92,29 +85,32 @@ where
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait RequestExt<State: Clone + Send + Sync + 'static>: Sized {
|
pub trait RequestExt<State: Clone + Send + Sync + 'static>: Sized {
|
||||||
/// Convert a query to `async_graphql::QueryBuilder`.
|
/// Convert a query to `async_graphql::QueryBuilder`.
|
||||||
async fn body_graphql(self) -> tide::Result<QueryBuilder> {
|
async fn body_graphql(self) -> tide::Result<async_graphql::Request> {
|
||||||
self.body_graphql_opts(Default::default()).await
|
self.body_graphql_opts(Default::default()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Similar to graphql, but you can set the options `IntoQueryBuilderOpts`.
|
/// Similar to graphql, but you can set the options `IntoQueryBuilderOpts`.
|
||||||
async fn body_graphql_opts(self, opts: ReceiveMultipartOptions) -> tide::Result<QueryBuilder>;
|
async fn body_graphql_opts(
|
||||||
|
self,
|
||||||
|
opts: MultipartOptions,
|
||||||
|
) -> tide::Result<async_graphql::Request>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<State: Clone + Send + Sync + 'static> RequestExt<State> for Request<State> {
|
impl<State: Clone + Send + Sync + 'static> RequestExt<State> for Request<State> {
|
||||||
async fn body_graphql_opts(self, opts: ReceiveMultipartOptions) -> tide::Result<QueryBuilder> {
|
async fn body_graphql_opts(
|
||||||
|
self,
|
||||||
|
opts: MultipartOptions,
|
||||||
|
) -> tide::Result<async_graphql::Request> {
|
||||||
if self.method() == Method::Get {
|
if self.method() == Method::Get {
|
||||||
let gql_request: GQLRequest = self.query::<GQLRequest>()?;
|
Ok(self.query::<GQLRequest>()?.into())
|
||||||
let builder = gql_request
|
|
||||||
.into_query_builder_opts(&opts)
|
|
||||||
.await
|
|
||||||
.status(StatusCode::BadRequest)?;
|
|
||||||
Ok(builder)
|
|
||||||
} else {
|
} else {
|
||||||
let content_type = self
|
let content_type = self
|
||||||
.header(&headers::CONTENT_TYPE)
|
.header(&headers::CONTENT_TYPE)
|
||||||
.and_then(|values| values.get(0).map(|value| value.to_string()));
|
.and_then(|values| values.get(0).map(|value| value.to_string()));
|
||||||
Ok((content_type, self).into_query_builder_opts(&opts).await?)
|
async_graphql::http::receive_body(content_type, self, opts)
|
||||||
|
.await
|
||||||
|
.map_err(|err| tide::Error::new(StatusCode::BadRequest, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,23 +119,22 @@ impl<State: Clone + Send + Sync + 'static> RequestExt<State> for Request<State>
|
|||||||
///
|
///
|
||||||
pub trait ResponseExt: Sized {
|
pub trait ResponseExt: Sized {
|
||||||
/// Set body as the result of a GraphQL query.
|
/// Set body as the result of a GraphQL query.
|
||||||
fn body_graphql(self, res: async_graphql::Result<Response>) -> tide::Result<Self>;
|
fn body_graphql(self, res: async_graphql::Response) -> tide::Result<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseExt for Response {
|
impl ResponseExt for Response {
|
||||||
fn body_graphql(self, res: async_graphql::Result<Response>) -> tide::Result<Self> {
|
fn body_graphql(self, res: async_graphql::Response) -> tide::Result<Self> {
|
||||||
let mut resp = add_cache_control(self, &res);
|
let mut resp = add_cache_control(self, &res);
|
||||||
resp.set_body(Body::from_json(&GQLResponse(res))?);
|
resp.set_body(Body::from_json(&res)?);
|
||||||
Ok(resp)
|
Ok(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_cache_control(mut http_resp: Response, resp: &async_graphql::Result<Response>) -> Response {
|
fn add_cache_control(mut http_resp: Response, resp: &async_graphql::Response) -> Response {
|
||||||
if let Ok(Response { cache_control, .. }) = resp {
|
if resp.is_ok() {
|
||||||
if let Some(cache_control) = cache_control.value() {
|
if let Some(cache_control) = resp.cache_control.value() {
|
||||||
if let Ok(header) = tide::http::headers::HeaderName::from_str("cache-control") {
|
if let Ok(header) = tide::http::headers::HeaderName::from_str("cache-control") {
|
||||||
http_resp.insert_header(header, cache_control);
|
http_resp.insert_header(header, cache_control);
|
||||||
return http_resp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,8 @@ fn quickstart() -> Result<()> {
|
|||||||
|
|
||||||
async fn graphql(req: Request<()>) -> tide::Result<Response> {
|
async fn graphql(req: Request<()>) -> tide::Result<Response> {
|
||||||
let schema = Schema::build(QueryRoot, EmptyMutation, EmptySubscription).finish();
|
let schema = Schema::build(QueryRoot, EmptyMutation, EmptySubscription).finish();
|
||||||
let query_builder = req.body_graphql().await?;
|
let request = req.body_graphql().await?;
|
||||||
Ok(Response::new(StatusCode::Ok)
|
Ok(Response::new(StatusCode::Ok).body_graphql(schema.execute(request).await)?)
|
||||||
.body_graphql(query_builder.execute(&schema).await)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut app = tide::new();
|
let mut app = tide::new();
|
||||||
|
@ -28,6 +28,7 @@ type HandleRequestBoxFut<'a> =
|
|||||||
|
|
||||||
type InitializerFn = Arc<dyn Fn(serde_json::Value) -> FieldResult<Data> + Send + Sync>;
|
type InitializerFn = Arc<dyn Fn(serde_json::Value) -> FieldResult<Data> + Send + Sync>;
|
||||||
|
|
||||||
|
/// Create a websocket transport.
|
||||||
pub fn create<Query, Mutation, Subscription>(
|
pub fn create<Query, Mutation, Subscription>(
|
||||||
schema: &Schema<Query, Mutation, Subscription>,
|
schema: &Schema<Query, Mutation, Subscription>,
|
||||||
) -> (mpsc::UnboundedSender<Vec<u8>>, impl Stream<Item = Vec<u8>>)
|
) -> (mpsc::UnboundedSender<Vec<u8>>, impl Stream<Item = Vec<u8>>)
|
||||||
@ -39,6 +40,7 @@ where
|
|||||||
create_with_initializer(schema, |_| Ok(Default::default()))
|
create_with_initializer(schema, |_| Ok(Default::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a websocket transport and specify a context initialization function.
|
||||||
pub fn create_with_initializer<Query, Mutation, Subscription>(
|
pub fn create_with_initializer<Query, Mutation, Subscription>(
|
||||||
schema: &Schema<Query, Mutation, Subscription>,
|
schema: &Schema<Query, Mutation, Subscription>,
|
||||||
initializer: impl Fn(serde_json::Value) -> FieldResult<Data> + Send + Sync + 'static,
|
initializer: impl Fn(serde_json::Value) -> FieldResult<Data> + Send + Sync + 'static,
|
||||||
|
Loading…
Reference in New Issue
Block a user