-
Notifications
You must be signed in to change notification settings - Fork 428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Axum integration #1088
Axum integration #1088
Changes from 5 commits
bc7f4a8
11ecc25
2932e6e
719eb97
183302c
f9326e5
59ab64a
7414b4c
e1a1104
fbef4c0
b5d5be8
f5b0d70
2691dc4
5f50474
224e30c
072717e
aa03df3
baea7e6
8961631
2a819fd
ac97a3a
4600686
3b3e7e3
4d89d51
ccac700
fa73e0b
5491556
90bcc3c
cac125f
afa9521
e2561c7
8ba8de5
c44f5cd
c9cf94e
bb6dcaa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
`juniper_axum` changelog | ||
======================== | ||
|
||
All user visible changes to `juniper_axum` crate will be documented in this file. This project uses [Semantic Versioning 2.0.0]. | ||
|
||
|
||
|
||
|
||
## master | ||
|
||
### BC Breaks | ||
|
||
- Switched to 0.16 version of [`juniper` crate]. | ||
|
||
|
||
|
||
|
||
## Previous releases | ||
|
||
See [old CHANGELOG](/../../blob/juniper_warp-v0.0.0/juniper_axum/CHANGELOG.md). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This mentions |
||
|
||
|
||
|
||
|
||
[`juniper` crate]: https://docs.rs/juniper | ||
[Semantic Versioning 2.0.0]: https://semver.org |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
[package] | ||
name = "juniper_axum" | ||
version = "0.1.0" | ||
edition = "2021" | ||
rust-version = "1.62" | ||
description = "`juniper` GraphQL integration with `axum`." | ||
license = "BSD-2-Clause" | ||
authors = ["Benno Tielen <[email protected]>"] | ||
documentation = "https://docs.rs/juniper_axum" | ||
homepage = "https://github.com/graphql-rust/juniper/tree/master/juniper_axum" | ||
repository = "https://github.com/graphql-rust/juniper" | ||
readme = "README.md" | ||
categories = ["asynchronous", "web-programming", "web-programming::http-server"] | ||
keywords = ["graphql", "juniper", "axum", "websocket"] | ||
exclude = ["/release.toml"] | ||
|
||
[dependencies] | ||
axum = { version = "0.5.11", features = ["ws"]} | ||
juniper = { path = "../juniper" } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is a version required? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @btielen in the same way as other integrations have. The version bump is automated with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned in the PR comments already, this should have a version and wired up to the release machinery. |
||
serde = "1.0" | ||
serde_json = "1.0" | ||
juniper_graphql_ws = { path="../juniper_graphql_ws" } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto. |
||
futures = "0.3" | ||
|
||
[dev-dependencies] | ||
tokio = { version = "1.20", features = ["full"] } | ||
tokio-tungstenite = "0.17.2" | ||
tokio-stream = "0.1.9" | ||
tower = "0.4.13" | ||
hyper = "0.14.20" | ||
juniper = { path = "../juniper", features = ["expose-test-schema"]} | ||
anyhow = "1.0" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
BSD 2-Clause License | ||
|
||
Copyright (c) 2022, Benno Tielen | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
|
||
* Redistributions of source code must retain the above copyright notice, this | ||
list of conditions and the following disclaimer. | ||
|
||
* Redistributions in binary form must reproduce the above copyright notice, | ||
this list of conditions and the following disclaimer in the documentation | ||
and/or other materials provided with the distribution. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
`juniper_axum` crate | ||
==================== | ||
|
||
[![Crates.io](https://img.shields.io/crates/v/juniper_axum.svg?maxAge=2592000)](https://crates.io/crates/juniper_warp) | ||
[![Documentation](https://docs.rs/juniper_warp/badge.svg)](https://docs.rs/juniper_warp) | ||
LegNeato marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[![CI](https://github.com/graphql-rust/juniper/workflows/CI/badge.svg?branch=master "CI")](https://github.com/graphql-rust/juniper/actions?query=workflow%3ACI+branch%3Amaster) | ||
|
||
- [Changelog](https://github.com/graphql-rust/juniper/blob/master/juniper_axum/CHANGELOG.md) | ||
|
||
[`axum`] web server integration for [`juniper`] ([GraphQL] implementation for [Rust]). | ||
|
||
## Getting started | ||
|
||
The best way to get started is to examine the `simple` example in the `examples` directory. To execute | ||
this example run | ||
|
||
`cargo run --example simple` | ||
|
||
Open your browser and navigate to `127.0.0.1:3000`. A GraphQL Playground opens. The | ||
following commands are available in the playground. | ||
|
||
```graphql | ||
{ | ||
add(a: 2, b: 40) | ||
} | ||
``` | ||
|
||
```graphql | ||
subscription { | ||
count | ||
} | ||
``` | ||
|
||
## Queries and mutations | ||
This crate provides an extractor and response for axum to work with juniper. | ||
|
||
```rust,ignore | ||
use juniper_axum::response::JuniperResponse; | ||
|
||
let app: Router<Body> = Router::new() | ||
.route("/graphql", post(graphql)) | ||
.layer(Extension(schema)) | ||
.layer(Extension(context)); | ||
|
||
async fn graphql( | ||
JuniperRequest(request): JuniperRequest, | ||
Extension(schema): Extension<Arc<Schema>>, | ||
Extension(context): Extension<Arc<Context>> | ||
) -> JuniperResponse { | ||
JuniperResponse(request.execute(&schema, &context).await) | ||
} | ||
``` | ||
|
||
## Subscriptions | ||
This crate provides a helper function to easily work with graphql subscriptions over a websocket. | ||
```rust,ignore | ||
use juniper_axum::subscription::handle_graphql_socket; | ||
|
||
let app: Router = Router::new() | ||
.route("/subscriptions", get(juniper_subscriptions)) | ||
.layer(Extension(schema)) | ||
.layer(Extension(context)); | ||
|
||
pub async fn juniper_subscriptions( | ||
Extension(schema): Extension<Arc<Schema>>, | ||
Extension(context): Extension<Context>, | ||
ws: WebSocketUpgrade, | ||
) -> Response { | ||
ws.protocols(["graphql-ws", "graphql-transport-ws"]) | ||
.max_frame_size(1024) | ||
.max_message_size(1024) | ||
.max_send_queue(100) | ||
.on_upgrade(|socket| handle_graphql_socket(socket, schema, context)) | ||
} | ||
``` | ||
|
||
|
||
|
||
## License | ||
|
||
This project is licensed under [BSD 2-Clause License](https://github.com/graphql-rust/juniper/blob/master/juniper_axum/LICENSE). | ||
|
||
|
||
|
||
|
||
[`juniper`]: https://docs.rs/juniper | ||
[`juniper_axum`]: https://docs.rs/juniper_axum | ||
[`axum`]: https://docs.rs/axum | ||
[GraphQL]: http://graphql.org | ||
[Juniper Book]: https://graphql-rust.github.io | ||
[Rust]: https://www.rust-lang.org | ||
|
||
[1]: https://github.com/graphql-rust/juniper/blob/master/juniper_warp/examples/warp_server.rs | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix URL. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use std::{net::SocketAddr, pin::Pin, sync::Arc, time::Duration}; | ||
|
||
use axum::{ | ||
extract::WebSocketUpgrade, | ||
response::Response, | ||
routing::{get, post}, | ||
Extension, Router, | ||
}; | ||
use futures::{Stream, StreamExt}; | ||
|
||
use juniper::{graphql_object, graphql_subscription, EmptyMutation, FieldError, RootNode}; | ||
use juniper_axum::{ | ||
extract::JuniperRequest, playground, response::JuniperResponse, | ||
subscriptions::handle_graphql_socket, | ||
}; | ||
|
||
#[derive(Clone)] | ||
pub struct Context; | ||
impl juniper::Context for Context {} | ||
|
||
#[derive(Clone, Copy, Debug)] | ||
pub struct Query; | ||
|
||
#[graphql_object(context = Context)] | ||
impl Query { | ||
/// Add two numbers a and b | ||
fn add(a: i32, b: i32) -> i32 { | ||
a + b | ||
} | ||
} | ||
|
||
pub struct Subscription; | ||
type NumberStream = Pin<Box<dyn Stream<Item = Result<i32, FieldError>> + Send>>; | ||
type AppSchema = RootNode<'static, Query, EmptyMutation<Context>, Subscription>; | ||
|
||
#[graphql_subscription(context = Context)] | ||
impl Subscription { | ||
/// Count seconds | ||
async fn count() -> NumberStream { | ||
let mut value = 0; | ||
let stream = tokio_stream::wrappers::IntervalStream::new(tokio::time::interval( | ||
Duration::from_secs(1), | ||
)) | ||
.map(move |_| { | ||
value += 1; | ||
Ok(value) | ||
}); | ||
Box::pin(stream) | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let schema = Arc::new(AppSchema::new(Query, EmptyMutation::new(), Subscription)); | ||
|
||
let context = Context; | ||
|
||
let app = Router::new() | ||
.route("/", get(|| playground("/graphql", Some("/subscriptions")))) | ||
.route("/graphql", post(graphql)) | ||
.route("/subscriptions", get(juniper_subscriptions)) | ||
.layer(Extension(schema)) | ||
.layer(Extension(context)); | ||
|
||
// run it | ||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); | ||
println!("listening on {}", addr); | ||
axum::Server::bind(&addr) | ||
.serve(app.into_make_service()) | ||
.await | ||
.unwrap(); | ||
} | ||
|
||
pub async fn juniper_subscriptions( | ||
Extension(schema): Extension<Arc<AppSchema>>, | ||
Extension(context): Extension<Context>, | ||
ws: WebSocketUpgrade, | ||
) -> Response { | ||
ws.protocols(["graphql-ws"]) | ||
.max_frame_size(1024) | ||
.max_message_size(1024) | ||
.max_send_queue(100) | ||
.on_upgrade(|socket| handle_graphql_socket(socket, schema, context)) | ||
} | ||
|
||
async fn graphql( | ||
JuniperRequest(request): JuniperRequest, | ||
Extension(schema): Extension<Arc<AppSchema>>, | ||
Extension(context): Extension<Context>, | ||
) -> JuniperResponse { | ||
JuniperResponse(request.execute(&schema, &context).await) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just remove this section and put something like: