From 14eed91fcd73aa65247e145ed394d86989a93ee3 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sun, 10 Mar 2019 19:19:50 -0700 Subject: [PATCH] update juniper and middleware examples --- basics/src/main.rs | 1 - juniper/Cargo.toml | 11 ++-- juniper/src/main.rs | 115 +++++++++++-------------------------- middleware/Cargo.toml | 8 ++- middleware/src/main.rs | 37 ++++++------ middleware/src/redirect.rs | 74 ++++++++++++++++++------ middleware/src/simple.rs | 76 ++++++++++++++++++------ 7 files changed, 170 insertions(+), 152 deletions(-) diff --git a/basics/src/main.rs b/basics/src/main.rs index 55f25bb..58eae45 100644 --- a/basics/src/main.rs +++ b/basics/src/main.rs @@ -77,7 +77,6 @@ fn with_param(req: HttpRequest, path: web::Path<(String,)>) -> HttpResponse { fn main() -> io::Result<()> { env::set_var("RUST_LOG", "actix_web=debug"); - env::set_var("RUST_BACKTRACE", "1"); env_logger::init(); let sys = actix_rt::System::new("basic-example"); diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index d19b352..e1295d2 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -2,17 +2,14 @@ name = "juniper-example" version = "0.1.0" authors = ["pyros2097 "] -workspace = "../" +workspace = ".." +edition = "2018" [dependencies] -env_logger = "0.5" - -actix = "0.7" -actix-web = "0.7" - +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +env_logger = "0.6" futures = "0.1" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" - juniper = "0.9.2" diff --git a/juniper/src/main.rs b/juniper/src/main.rs index 468c093..34967eb 100644 --- a/juniper/src/main.rs +++ b/juniper/src/main.rs @@ -1,110 +1,59 @@ //! Actix web juniper example //! //! A simple example integrating juniper in actix-web -extern crate serde; -extern crate serde_json; -#[macro_use] -extern crate serde_derive; +use std::io; +use std::sync::Arc; + #[macro_use] extern crate juniper; -extern crate actix; -extern crate actix_web; -extern crate env_logger; -extern crate futures; -use actix::prelude::*; -use actix_web::{ - http, middleware, server, App, AsyncResponder, Error, FutureResponse, HttpRequest, - HttpResponse, Json, State, -}; +use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; use futures::future::Future; use juniper::http::graphiql::graphiql_source; use juniper::http::GraphQLRequest; mod schema; -use schema::create_schema; -use schema::Schema; +use crate::schema::{create_schema, Schema}; -struct AppState { - executor: Addr, -} - -#[derive(Serialize, Deserialize)] -pub struct GraphQLData(GraphQLRequest); - -impl Message for GraphQLData { - type Result = Result; -} - -pub struct GraphQLExecutor { - schema: std::sync::Arc, -} - -impl GraphQLExecutor { - fn new(schema: std::sync::Arc) -> GraphQLExecutor { - GraphQLExecutor { schema: schema } - } -} - -impl Actor for GraphQLExecutor { - type Context = SyncContext; -} - -impl Handler for GraphQLExecutor { - type Result = Result; - - fn handle(&mut self, msg: GraphQLData, _: &mut Self::Context) -> Self::Result { - let res = msg.0.execute(&self.schema, &()); - let res_text = serde_json::to_string(&res)?; - Ok(res_text) - } -} - -fn graphiql(_req: &HttpRequest) -> Result { +fn graphiql() -> HttpResponse { let html = graphiql_source("http://127.0.0.1:8080/graphql"); - Ok(HttpResponse::Ok() + HttpResponse::Ok() .content_type("text/html; charset=utf-8") - .body(html)) + .body(html) } fn graphql( - (st, data): (State, Json), -) -> FutureResponse { - st.executor - .send(data.0) - .from_err() - .and_then(|res| match res { - Ok(user) => Ok(HttpResponse::Ok() - .content_type("application/json") - .body(user)), - Err(_) => Ok(HttpResponse::InternalServerError().into()), - }) - .responder() + st: web::State>, + data: web::Json, +) -> impl Future { + web::block(move || { + let res = data.execute(&st, &()); + Ok::<_, serde_json::error::Error>(serde_json::to_string(&res)?) + }) + .map_err(Error::from) + .and_then(|user| { + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(user)) + }) } -fn main() { - ::std::env::set_var("RUST_LOG", "actix_web=info"); +fn main() -> io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); - let sys = actix::System::new("juniper-example"); + // Create Juniper schema let schema = std::sync::Arc::new(create_schema()); - let addr = SyncArbiter::start(3, move || GraphQLExecutor::new(schema.clone())); // Start http server - server::new(move || { - App::with_state(AppState { - executor: addr.clone(), - }) - // enable logger - .middleware(middleware::Logger::default()) - .resource("/graphql", |r| r.method(http::Method::POST).with(graphql)) - .resource("/graphiql", |r| r.method(http::Method::GET).h(graphiql)) + HttpServer::new(move || { + App::new() + .state(schema.clone()) + .middleware(middleware::Logger::default()) + .service(web::resource("/graphql").route(web::post().to_async(graphql))) + .service(web::resource("/graphiql").route(web::get().to(graphiql))) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8080"); - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/middleware/Cargo.toml b/middleware/Cargo.toml index b14354f..2d533c8 100644 --- a/middleware/Cargo.toml +++ b/middleware/Cargo.toml @@ -2,7 +2,11 @@ name = "middleware-example" version = "0.1.0" authors = ["Gorm Casper "] +edition = "2018" +workspace = ".." [dependencies] -actix = "0.7" -actix-web = "0.7" +actix-service = "0.3.3" +actix-web = { git="https://github.com/actix/actix-web.git", branch = "1.0" } +futures = "0.1.25" +env_logger = "0.6" \ No newline at end of file diff --git a/middleware/src/main.rs b/middleware/src/main.rs index 91ae9d0..6e1ec82 100644 --- a/middleware/src/main.rs +++ b/middleware/src/main.rs @@ -1,32 +1,27 @@ -extern crate actix; -extern crate actix_web; - -use actix_web::{server, App}; +use actix_web::{web, App, HttpServer}; #[allow(dead_code)] mod redirect; #[allow(dead_code)] mod simple; -fn main() { - let sys = actix::System::new("middleware-example"); +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=debug"); + env_logger::init(); - let _addr = server::new(|| { + HttpServer::new(|| { App::new() + .middleware(redirect::CheckLogin) .middleware(simple::SayHi) - // .middleware(redirect::CheckLogin) - .resource("/login", |r| { - r.f(|_| { - "You are on /login. Go to src/redirect.rs to change this behavior." - }) - }) - .resource("/", |r| { - r.f(|_| "Hello, middleware! Check the console where the server is run.") - }) + .service(web::resource("/login").to(|| { + "You are on /login. Go to src/redirect.rs to change this behavior." + })) + .service( + web::resource("/").to(|| { + "Hello, middleware! Check the console where the server is run." + }), + ) }) - .bind("127.0.0.1:8080") - .unwrap() - .start(); - - let _ = sys.run(); + .bind("127.0.0.1:8080")? + .run() } diff --git a/middleware/src/redirect.rs b/middleware/src/redirect.rs index a0d5de6..3ffd3a8 100644 --- a/middleware/src/redirect.rs +++ b/middleware/src/redirect.rs @@ -1,28 +1,64 @@ -extern crate actix_web; - -use actix_web::middleware::{Middleware, Started}; -use actix_web::{http, HttpRequest, HttpResponse, Result}; +use actix_service::{Service, Transform}; +use actix_web::dev::{ServiceRequest, ServiceResponse}; +use actix_web::{http, HttpResponse}; +use futures::future::{ok, Either, FutureResult}; +use futures::Poll; pub struct CheckLogin; -impl Middleware for CheckLogin { - // We only need to hook into the `start` for this middleware. - fn start(&self, req: &HttpRequest) -> Result { +impl Transform for CheckLogin +where + S: Service, Response = ServiceResponse>, + S::Future: 'static, +{ + type Request = ServiceRequest

; + type Response = ServiceResponse; + type Error = S::Error; + type InitError = (); + type Transform = CheckLoginMiddleware; + type Future = FutureResult; + + fn new_transform(&self, service: S) -> Self::Future { + ok(CheckLoginMiddleware { service }) + } +} +pub struct CheckLoginMiddleware { + service: S, +} + +impl Service for CheckLoginMiddleware +where + S: Service, Response = ServiceResponse>, + S::Future: 'static, +{ + type Request = ServiceRequest

; + type Response = ServiceResponse; + type Error = S::Error; + type Future = Either>; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + self.service.poll_ready() + } + + fn call(&mut self, req: ServiceRequest

) -> Self::Future { + // We only need to hook into the `start` for this middleware. + let is_logged_in = false; // Change this to see the change in outcome in the browser if is_logged_in { - return Ok(Started::Done); + Either::A(self.service.call(req)) + } else { + // Don't forward to /login if we are already on /login + if req.path() == "/login" { + Either::A(self.service.call(req)) + } else { + Either::B(ok(req.into_response( + HttpResponse::Found() + .header(http::header::LOCATION, "/login") + .finish() + .into_body(), + ))) + } } - - // Don't forward to /login if we are already on /login - if req.path() == "/login" { - return Ok(Started::Done); - } - - Ok(Started::Response( - HttpResponse::Found() - .header(http::header::LOCATION, "/login") - .finish(), - )) } } diff --git a/middleware/src/simple.rs b/middleware/src/simple.rs index 254f263..68f6e14 100644 --- a/middleware/src/simple.rs +++ b/middleware/src/simple.rs @@ -1,25 +1,63 @@ -extern crate actix_web; +use actix_service::{Service, Transform}; +use actix_web::dev::{ServiceRequest, ServiceResponse}; +use futures::future::{ok, FutureResult}; +use futures::{Future, Poll}; -use actix_web::middleware::{Finished, Middleware, Response, Started}; -use actix_web::{HttpRequest, HttpResponse, Result}; - -// Middleware can get called at three stages during the request/response handling. Below is a -// struct that implements all three of them. +// There are two step in middleware processing. +// 1. Middleware initialization, middleware factory get called with +// next service in chain as parameter. +// 2. Middleware's call method get called with normal request. pub struct SayHi; -impl Middleware for SayHi { - fn start(&self, req: &HttpRequest) -> Result { - println!("Hi from start. You requested: {}", req.path()); - Ok(Started::Done) - } +// Middleware factory is `Transform` trait from actix-service crate +// `S` - type of the next service +// `P` - type of request's payload +// `B` - type of response's body +impl Transform for SayHi +where + S: Service, Response = ServiceResponse>, + S::Future: 'static, + S::Error: 'static, + B: 'static, +{ + type Request = ServiceRequest

; + type Response = ServiceResponse; + type Error = S::Error; + type InitError = (); + type Transform = SayHiMiddleware; + type Future = FutureResult; - fn response(&self, _req: &HttpRequest, resp: HttpResponse) -> Result { - println!("Hi from response"); - Ok(Response::Done(resp)) - } - - fn finish(&self, _req: &HttpRequest, _resp: &HttpResponse) -> Finished { - println!("Hi from finish"); - Finished::Done + fn new_transform(&self, service: S) -> Self::Future { + ok(SayHiMiddleware { service }) + } +} + +pub struct SayHiMiddleware { + service: S, +} + +impl Service for SayHiMiddleware +where + S: Service, Response = ServiceResponse>, + S::Future: 'static, + S::Error: 'static, + B: 'static, +{ + type Request = ServiceRequest

; + type Response = ServiceResponse; + type Error = S::Error; + type Future = Box>; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + self.service.poll_ready() + } + + fn call(&mut self, req: ServiceRequest

) -> Self::Future { + println!("Hi from start. You requested: {}", req.path()); + + Box::new(self.service.call(req).and_then(|res| { + println!("Hi from response"); + Ok(res) + })) } }