Skip to content

Commit

Permalink
Cleaner Axum Integration (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkonkle authored Jul 15, 2024
1 parent 61766fa commit 86b80c7
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 122 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.21.0]

### Changed

- `nakago-axum` - Changed the `Inject` extractor to be a wrapper around the Nakago dependency injection container, rather than a direct extractor. This makes it much more convenient to use it in an idiomatic way with Axum.
- `nakago-async-graphql` - Updated `nakago-axum`
- `nakago-ws` - Updated `nakago-axum`
- `nakago-examples-async-graphql` - Updated the example to use the new `Inject` extractor.

## [0.20.0]

### Added
Expand Down Expand Up @@ -347,7 +356,8 @@ Expect major changes to the Application and Lifecycle systems going forward, bui
- Injection Providers
- Documentation

[unreleased]: https://github.com/bkonkle/nakago/compare/0.20.0...HEAD
[unreleased]: https://github.com/bkonkle/nakago/compare/0.21.0...HEAD
[0.21.0]: https://github.com/bkonkle/nakago/compare/0.20.0...0.21.0
[0.20.0]: https://github.com/bkonkle/nakago/compare/0.19.1...0.20.0
[0.19.1]: https://github.com/bkonkle/nakago/compare/0.19.0...0.19.1
[0.19.0]: https://github.com/bkonkle/nakago/compare/0.18.0...0.19.0
Expand Down
8 changes: 4 additions & 4 deletions examples/async-graphql/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nakago-examples-async-graphql"
version = "0.20.0"
version = "0.21.0"
authors = ["Brandon Konkle <brandon@konkle.us>"]
edition = "2021"
description = "A lightweight Rust framework for sharp services 😎"
Expand Down Expand Up @@ -34,11 +34,11 @@ futures = "0.3"
hyper = "1.0"
log = "0.4"
nakago = "0.20"
nakago-async-graphql = "0.20"
nakago-axum = "0.20"
nakago-async-graphql = "0.21"
nakago-axum = "0.21"
nakago-derive = "0.20"
nakago-sea-orm = "0.20"
nakago-ws = "0.20"
nakago-ws = "0.21"
oso = "0.27"
pico-args = "0.5.0"
pretty_env_logger = "0.5"
Expand Down
77 changes: 23 additions & 54 deletions examples/async-graphql/src/http/graphql.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,31 @@
use std::sync::Arc;

use async_graphql::http::GraphiQLSource;
use async_graphql_axum::{GraphQLRequest, GraphQLResponse};
use async_trait::async_trait;
use axum::response::{Html, IntoResponse};
use nakago::{provider, Inject, Provider};
use nakago_axum::auth::Subject;
use nakago_derive::Provider;
use axum::response::{self, IntoResponse};
use nakago_axum::{auth::Subject, Inject};

use crate::domains::{graphql, users};

/// Events Controller
#[derive(Clone)]
pub struct Controller {
users: Arc<Box<dyn users::Service>>,
schema: Arc<graphql::Schema>,
}

impl Controller {
/// Handle GraphiQL Requests
pub async fn graphiql() -> impl IntoResponse {
Html(GraphiQLSource::build().endpoint("/graphql").finish())
}

/// Handle GraphQL Requests
pub async fn resolve(
self: Arc<Self>,
sub: Subject,
req: GraphQLRequest,
) -> Result<GraphQLResponse, GraphQLResponse> {
// Retrieve the request User, if username is present
let user = if let Subject(Some(ref username)) = sub {
self.users
.get_by_username(username, &true)
.await
.unwrap_or(None)
} else {
None
};

// Add the Subject and optional User to the context
let request = req.into_inner().data(sub).data(user);

Ok(self.schema.execute(request).await.into())
}
/// Handle GraphQL Requests
pub async fn resolve(
schema: Inject<graphql::Schema>,
users: Inject<Box<dyn users::Service>>,
sub: Subject,
req: GraphQLRequest,
) -> GraphQLResponse {
// Retrieve the request User, if username is present
let user = if let Subject(Some(ref username)) = sub {
users.get_by_username(username, &true).await.unwrap_or(None)
} else {
None
};

// Add the Subject and optional User to the context
let request = req.into_inner().data(sub).data(user);

schema.execute(request).await.into()
}

/// Events Provider
#[derive(Default)]
pub struct Provide {}

#[Provider]
#[async_trait]
impl Provider<Controller> for Provide {
async fn provide(self: Arc<Self>, i: Inject) -> provider::Result<Arc<Controller>> {
let users = i.get::<Box<dyn users::Service>>().await?;
let schema = i.get::<graphql::Schema>().await?;

Ok(Arc::new(Controller { users, schema }))
}
/// Handle GraphiQL UI Requests
pub async fn graphiql() -> impl IntoResponse {
response::Html(GraphiQLSource::build().endpoint("/").finish())
}
24 changes: 4 additions & 20 deletions examples/async-graphql/src/http/init.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use async_trait::async_trait;
use axum::{
routing::{get, post},
Router,
};
use axum::{routing::get, Router};
use nakago::{hooks, Hook, Inject};
use nakago_axum::routes;
use nakago_ws::{connections, controller};
Expand All @@ -18,9 +15,6 @@ pub struct Load {}
#[async_trait]
impl Hook for Load {
async fn handle(&self, i: Inject) -> hooks::Result<()> {
i.provide::<graphql::Controller>(graphql::Provide::default())
.await?;

i.provide::<nakago_ws::Connections<User>>(connections::Provide::default())
.await?;

Expand All @@ -41,25 +35,15 @@ pub struct Init {}
#[async_trait]
impl Hook for Init {
async fn handle(&self, i: Inject) -> hooks::Result<()> {
let graphql_controller = i.get::<graphql::Controller>().await?;
let events_controller = i.get::<nakago_ws::Controller<User>>().await?;

i.handle(routes::Init::new(
Router::new().route("/health", get(health::health_check)),
))
.await?;

i.handle(routes::Init::new(
Router::new().route("/graphql", get(graphql::Controller::graphiql)),
Router::new()
.route("/health", get(health::health_check))
.route("/graphql", get(graphql::graphiql).post(graphql::resolve)),
))
.await?;

i.handle(routes::Init::new(Router::new().route(
"/graphql",
post(move |sub, req| async move { graphql_controller.resolve(sub, req).await }),
)))
.await?;

i.handle(routes::Init::new(Router::new().route(
"/events",
get(move |sub, ws| async move { events_controller.upgrade(sub, ws).await }),
Expand Down
34 changes: 14 additions & 20 deletions examples/async-graphql/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,22 @@ struct Args {
config_path: Option<PathBuf>,
}

impl Args {
pub fn parse() -> Result<Args, Error> {
let mut pargs = Arguments::from_env();

let args = Args {
help: pargs.contains(["-h", "--help"]),
config_path: pargs.opt_value_from_str(["-c", "--config"])?,
};

Ok(args)
}
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = parse_args()?;
let args = Args::parse()?;

if args.help {
println!("{}", HELP);
Expand All @@ -54,22 +67,3 @@ async fn main() -> anyhow::Result<()> {

Ok(())
}

fn parse_args() -> Result<Args, Error> {
let mut pargs = Arguments::from_env();

let args = Args {
help: pargs.contains(["-h", "--help"]),
config_path: pargs.opt_value_from_os_str("-c", parse_path)?.or_else(|| {
pargs
.opt_value_from_os_str("--config", parse_path)
.unwrap_or_default()
}),
};

Ok(args)
}

fn parse_path(s: &std::ffi::OsStr) -> Result<std::path::PathBuf, &'static str> {
Ok(s.into())
}
2 changes: 1 addition & 1 deletion examples/simple/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ futures = "0.3"
hyper = "1.0"
log = "0.4"
nakago = "0.20"
nakago-axum = "0.20"
nakago-axum = "0.21"
nakago-derive = "0.20"
pico-args = "0.5.0"
pretty_env_logger = "0.5"
Expand Down
4 changes: 2 additions & 2 deletions nakago_async_graphql/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nakago-async-graphql"
version = "0.20.0"
version = "0.21.0"
authors = ["Brandon Konkle <brandon@konkle.us>"]
edition = "2021"
description = "An Async-GraphQL integration for Nakago"
Expand Down Expand Up @@ -29,7 +29,7 @@ figment = { version = "0.10", features = ["env"] }
hyper = "1.0"
log = "0.4"
nakago = "0.20"
nakago-axum = "0.20"
nakago-axum = "0.21"
nakago-derive = "0.20"
pretty_env_logger = "0.5"
rand = "0.8"
Expand Down
2 changes: 1 addition & 1 deletion nakago_axum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nakago-axum"
version = "0.20.0"
version = "0.21.0"
authors = ["Brandon Konkle <brandon@konkle.us>"]
edition = "2021"
description = "An Axum HTTP routes integration for Nakago"
Expand Down
35 changes: 18 additions & 17 deletions nakago_axum/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{
any::Any,
convert::Infallible,
ops::{Deref, DerefMut},
sync::Arc,
};

use async_trait::async_trait;
Expand All @@ -27,31 +29,30 @@ impl DerefMut for State {
}
}

/// An extractor for the injection container
pub struct Inject(pub nakago::Inject);
/// An Axum extractor to inject dependencies from Nakago
#[derive(new)]
pub struct Inject<T> {
inner: Arc<T>,
}

impl<T> Deref for Inject<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.inner
}
}

#[async_trait]
impl FromRequestParts<State> for Inject {
impl<T: Send + Sync + Any> FromRequestParts<State> for Inject<T> {
type Rejection = Infallible;

async fn from_request_parts(
_parts: &mut Parts,
state: &State,
) -> Result<Self, Self::Rejection> {
Ok(Self(state.i.clone()))
}
}
let t = state.get::<T>().await.unwrap();

impl Deref for Inject {
type Target = nakago::Inject;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for Inject {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
Ok(Self::new(t))
}
}
4 changes: 2 additions & 2 deletions nakago_ws/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nakago-ws"
version = "0.20.0"
version = "0.21.0"
authors = ["Brandon Konkle <brandon@konkle.us>"]
edition = "2021"
description = "Websocket utils for Nakago"
Expand All @@ -26,7 +26,7 @@ hyper = "1.0"
jsonwebtoken = "9.0"
log = "0.4"
nakago = "0.20"
nakago-axum = "0.20"
nakago-axum = "0.21"
nakago-derive = "0.20"
mockall = "0.12"
pretty_env_logger = "0.5"
Expand Down

0 comments on commit 86b80c7

Please sign in to comment.