diff --git a/Cargo.lock b/Cargo.lock index ef954a3..e42cf93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1040,6 +1040,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" +[[package]] +name = "ascii_utils" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" + [[package]] name = "askama" version = "0.11.1" @@ -1101,9 +1107,9 @@ dependencies = [ [[package]] name = "async-graphql" -version = "2.11.3" +version = "3.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6a9edeab4427f8162ac1ccd49152fa656affab3ccfaed7eeaf8e2f9ce12ee0" +checksum = "d1a994a60389a32a31304e46d437a11db46d5bbeb8c26de3dbfa309efd8b93e4" dependencies = [ "async-graphql-derive", "async-graphql-parser", @@ -1111,12 +1117,14 @@ dependencies = [ "async-stream", "async-trait", "bytes 1.1.0", + "fast_chemail", "fnv", "futures-util", "http", "indexmap", "mime", "multer", + "num-traits 0.2.14", "once_cell", "pin-project-lite 0.2.8", "regex", @@ -1129,40 +1137,46 @@ dependencies = [ [[package]] name = "async-graphql-actix-web" -version = "2.11.3" +version = "3.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8a626bab0bda64c520a8133b8fda8ea6762bc58f25c4b550311362e4b4f950" +checksum = "eb7df7399ff10b17ced5104c1046152ec8a05f3c8facb3b671fbe72ffed0c3ad" dependencies = [ - "actix 0.10.0", - "actix-http 2.2.2", - "actix-web 3.3.3", - "actix-web-actors 3.0.0", + "actix 0.12.0", + "actix-http 3.0.0-rc.3", + "actix-web 4.0.0-rc.3", + "actix-web-actors 4.0.0-beta.12", "async-channel", "async-graphql", + "futures-channel", "futures-util", "serde_json", "serde_urlencoded", + "thiserror", ] [[package]] name = "async-graphql-demo" version = "1.0.0" dependencies = [ - "actix-web 3.3.3", + "actix-cors", + "actix-web 4.0.0-rc.3", + "actix-web-lab", "async-graphql", "async-graphql-actix-web", + "env_logger 0.9.0", + "log", "slab", ] [[package]] name = "async-graphql-derive" -version = "2.11.3" +version = "3.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8be34933c1bca0b5aedb6d8b66ad3e27045eb8304f198cc1efaed6b6dd87835" +checksum = "71011bef5fef3019016b17fb8ba588d562c128d2d7ea93c86093352d5fd51ccf" dependencies = [ "Inflector", "async-graphql-parser", - "darling 0.12.4", + "darling", "proc-macro-crate", "proc-macro2", "quote", @@ -1172,9 +1186,9 @@ dependencies = [ [[package]] name = "async-graphql-parser" -version = "2.11.3" +version = "3.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99841c1f890fda6712054e7e37b207738f4aa97870cb1bffcab2f09f2df0957a" +checksum = "13b4caccb492c65240591a193c3e90ac11018dd25670544ce07360b7116c6153" dependencies = [ "async-graphql-value", "pest", @@ -1185,9 +1199,9 @@ dependencies = [ [[package]] name = "async-graphql-value" -version = "2.11.3" +version = "3.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cecac7ab6737364cff7b16e9273dd51fac7cfbd14ab5d84127df5a56ca9d422" +checksum = "30cd0d73a5a13fe9d1a7d5dd67c6394663dd531afb26a0c50c5da5b29cf7ba1f" dependencies = [ "bytes 1.1.0", "indexmap", @@ -2086,38 +2100,14 @@ dependencies = [ "cipher", ] -[[package]] -name = "darling" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" -dependencies = [ - "darling_core 0.12.4", - "darling_macro 0.12.4", -] - [[package]] name = "darling" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" dependencies = [ - "darling_core 0.13.1", - "darling_macro 0.13.1", -] - -[[package]] -name = "darling_core" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", + "darling_core", + "darling_macro", ] [[package]] @@ -2134,24 +2124,13 @@ dependencies = [ "syn", ] -[[package]] -name = "darling_macro" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" -dependencies = [ - "darling_core 0.12.4", - "quote", - "syn", -] - [[package]] name = "darling_macro" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" dependencies = [ - "darling_core 0.13.1", + "darling_core", "quote", "syn", ] @@ -2453,6 +2432,15 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +[[package]] +name = "fast_chemail" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4" +dependencies = [ + "ascii_utils", +] + [[package]] name = "fastrand" version = "1.7.0" @@ -5420,7 +5408,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e" dependencies = [ - "darling 0.13.1", + "darling", "proc-macro2", "quote", "syn", diff --git a/Cargo.toml b/Cargo.toml index db90ab6..5b33487 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ members = [ "forms/form", "forms/multipart-s3", "forms/multipart", - "graphql/graphql-demo", + "graphql/async-graphql", "graphql/juniper-advanced", "graphql/juniper", "json/json_decode_error", diff --git a/graphql/async-graphql/Cargo.toml b/graphql/async-graphql/Cargo.toml new file mode 100644 index 0000000..4a9f0bd --- /dev/null +++ b/graphql/async-graphql/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "async-graphql-demo" +version = "1.0.0" +edition = "2021" + +[dependencies] +actix-web = "4.0.0-rc.3" +actix-web-lab = "0.10" +actix-cors = "0.6.0-beta.10" + +async-graphql = "3" +async-graphql-actix-web = "3" + +env_logger = "0.9" +log = "0.4" +slab = "0.4.2" diff --git a/graphql/async-graphql/README.md b/graphql/async-graphql/README.md new file mode 100644 index 0000000..eda44b9 --- /dev/null +++ b/graphql/async-graphql/README.md @@ -0,0 +1,38 @@ +## GraphQL using `async-graphql` + +> Getting started using [async-graphql](https://github.com/async-graphql/async-graphql) with Actix Web. + +## Usage + +```bash +cd graphql/graphql-demo +cargo run +``` + +## Endpoints + +``` +GET/POST http://localhost:8080/graphql GraphQL endpoint +GET http://localhost:8080/graphiql GraphQL playground UI +``` + +## Query Examples + +```graphql +{ + humans { + edges { + node { + id + name + friends { + id + name + } + appearsIn + homePlanet + } + } + } +} +``` diff --git a/graphql/async-graphql/src/main.rs b/graphql/async-graphql/src/main.rs new file mode 100644 index 0000000..fe2a04d --- /dev/null +++ b/graphql/async-graphql/src/main.rs @@ -0,0 +1,53 @@ +use actix_cors::Cors; +use actix_web::{get, middleware::Logger, route, web, App, HttpServer, Responder}; +use actix_web_lab::respond::Html; +use async_graphql::{ + http::{playground_source, GraphQLPlaygroundConfig}, + EmptyMutation, EmptySubscription, Schema, +}; +use async_graphql_actix_web::{GraphQLRequest, GraphQLResponse}; + +mod star_wars; +use self::star_wars::{QueryRoot, StarWars, StarWarsSchema}; + +/// GraphQL endpoint +#[route("/graphql", method = "GET", method = "POST")] +async fn graphql( + schema: web::Data, + req: GraphQLRequest, +) -> GraphQLResponse { + schema.execute(req.into_inner()).await.into() +} + +/// GraphiQL playground UI +#[get("/graphiql")] +async fn graphql_playground() -> impl Responder { + Html(playground_source( + GraphQLPlaygroundConfig::new("/graphql").subscription_endpoint("/graphql"), + )) +} + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); + + let schema = Schema::build(QueryRoot, EmptyMutation, EmptySubscription) + .data(StarWars::new()) + .finish(); + + log::info!("starting HTTP server on port 8080"); + log::info!("GraphiQL playground: http://localhost:8080/graphiql"); + + HttpServer::new(move || { + App::new() + .app_data(web::Data::new(schema.clone())) + .service(graphql) + .service(graphql_playground) + .wrap(Cors::permissive()) + .wrap(Logger::default()) + }) + .workers(2) + .bind(("127.0.0.1", 8080))? + .run() + .await +} diff --git a/graphql/graphql-demo/src/starwars/mod.rs b/graphql/async-graphql/src/star_wars/mod.rs similarity index 99% rename from graphql/graphql-demo/src/starwars/mod.rs rename to graphql/async-graphql/src/star_wars/mod.rs index 53a54fc..eb1b7a2 100644 --- a/graphql/graphql-demo/src/starwars/mod.rs +++ b/graphql/async-graphql/src/star_wars/mod.rs @@ -1,13 +1,14 @@ -mod model; +use std::collections::HashMap; use async_graphql::{EmptyMutation, EmptySubscription, Schema}; use model::Episode; use slab::Slab; -use std::collections::HashMap; -pub use model::QueryRoot; pub type StarWarsSchema = Schema; +mod model; +pub use self::model::QueryRoot; + pub struct StarWarsChar { id: &'static str, name: &'static str, diff --git a/graphql/graphql-demo/src/starwars/model.rs b/graphql/async-graphql/src/star_wars/model.rs similarity index 99% rename from graphql/graphql-demo/src/starwars/model.rs rename to graphql/async-graphql/src/star_wars/model.rs index 9acb2de..919de99 100644 --- a/graphql/graphql-demo/src/starwars/model.rs +++ b/graphql/async-graphql/src/star_wars/model.rs @@ -1,7 +1,8 @@ -use super::StarWars; use async_graphql::connection::{query, Connection, Edge, EmptyFields}; use async_graphql::{Context, Enum, FieldResult, Interface, Object}; +use super::StarWars; + /// One of the films in the Star Wars Trilogy #[derive(Enum, Copy, Clone, Eq, PartialEq)] pub enum Episode { @@ -218,7 +219,8 @@ async fn query_characters( .enumerate() .map(|(idx, item)| Edge::new(start + idx, *item)), ); - Ok(connection) + + FieldResult::Ok(connection) }, ) .await diff --git a/graphql/graphql-demo/Cargo.toml b/graphql/graphql-demo/Cargo.toml deleted file mode 100644 index 90c7484..0000000 --- a/graphql/graphql-demo/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "async-graphql-demo" -version = "1.0.0" -edition = "2021" - -[dependencies] -actix-web = "3.0.0" -async-graphql = "2.0.0" -async-graphql-actix-web = "2.0.0" -slab = "0.4.2" diff --git a/graphql/graphql-demo/README.md b/graphql/graphql-demo/README.md deleted file mode 100644 index 9b18f9f..0000000 --- a/graphql/graphql-demo/README.md +++ /dev/null @@ -1,34 +0,0 @@ -Getting started using [Async-graphql](https://github.com/async-graphql/async-graphql) with Actix Web. - -## Run - -```bash -cd graphql/graphql-demo -cargo run --bin async-graphql-demo -``` - -## Endpoints - - GET http://127.0.0.1:8000/ GraphQL Playground UI - POST http://127.0.0.1:8000/ For GraphQL query - -## Query Examples - -```graphql -{ - humans { - edges { - node { - id - name - friends { - id - name - } - appearsIn - homePlanet - } - } - } -} -``` diff --git a/graphql/graphql-demo/src/main.rs b/graphql/graphql-demo/src/main.rs deleted file mode 100644 index 5d7f8e6..0000000 --- a/graphql/graphql-demo/src/main.rs +++ /dev/null @@ -1,38 +0,0 @@ -mod starwars; - -use actix_web::{guard, web, App, HttpResponse, HttpServer, Result}; -use async_graphql::http::{playground_source, GraphQLPlaygroundConfig}; -use async_graphql::{EmptyMutation, EmptySubscription, Schema}; -use async_graphql_actix_web::{Request, Response}; -use starwars::{QueryRoot, StarWars, StarWarsSchema}; - -async fn index(schema: web::Data, req: Request) -> Response { - schema.execute(req.into_inner()).await.into() -} - -async fn index_playground() -> Result { - Ok(HttpResponse::Ok() - .content_type("text/html; charset=utf-8") - .body(playground_source( - GraphQLPlaygroundConfig::new("/").subscription_endpoint("/"), - ))) -} - -#[actix_web::main] -async fn main() -> std::io::Result<()> { - let schema = Schema::build(QueryRoot, EmptyMutation, EmptySubscription) - .data(StarWars::new()) - .finish(); - - println!("Playground: http://localhost:8000"); - - HttpServer::new(move || { - App::new() - .data(schema.clone()) - .service(web::resource("/").guard(guard::Post()).to(index)) - .service(web::resource("/").guard(guard::Get()).to(index_playground)) - }) - .bind("127.0.0.1:8000")? - .run() - .await -} diff --git a/graphql/juniper-advanced/README.md b/graphql/juniper-advanced/README.md index 139ef45..4ffa9bb 100644 --- a/graphql/juniper-advanced/README.md +++ b/graphql/juniper-advanced/README.md @@ -1,4 +1,4 @@ -# juniper-advanced +# GraphQL using Juniper and MySQL GraphQL Implementation in Rust using Actix, Juniper, and MySQL as Database diff --git a/graphql/juniper-advanced/src/main.rs b/graphql/juniper-advanced/src/main.rs index 1cfe895..ec12e5f 100644 --- a/graphql/juniper-advanced/src/main.rs +++ b/graphql/juniper-advanced/src/main.rs @@ -18,7 +18,7 @@ async fn main() -> std::io::Result<()> { let pool = get_db_pool(); log::info!("starting HTTP server on port 8080"); - log::info!("the GraphiQL interface HTTP server at http://localhost:8080/graphiql"); + log::info!("GraphiQL playground: http://localhost:8080/graphiql"); HttpServer::new(move || { App::new() diff --git a/graphql/juniper/README.md b/graphql/juniper/README.md index 1a70f46..9515e64 100644 --- a/graphql/juniper/README.md +++ b/graphql/juniper/README.md @@ -1,4 +1,4 @@ -# Juniper +# GraphQL using Juniper [Juniper](https://github.com/graphql-rust/juniper) integration for Actix Web. If you want more advanced example, see also the [juniper-advanced example]. diff --git a/graphql/juniper/src/main.rs b/graphql/juniper/src/main.rs index 89e2e3b..3001903 100644 --- a/graphql/juniper/src/main.rs +++ b/graphql/juniper/src/main.rs @@ -40,7 +40,8 @@ async fn main() -> io::Result<()> { // Create Juniper schema let schema = Arc::new(create_schema()); - log::info!("starting HTTP server at http://localhost:8080"); + log::info!("starting HTTP server on port 8080"); + log::info!("GraphiQL playground: http://localhost:8080/graphiql"); // Start HTTP server HttpServer::new(move || {