🥠 Sessions as a `tower` and `axum` middleware.

Overview

tower-sessions

🥠 Sessions as a `tower` and `axum` middleware.

🎨 Overview

This crate provides sessions, key-value pairs associated with a site visitor, as a tower middleware.

It offers:

  • Pluggable Storage Backends: Arbitrary storage backends are implemented with the SessionStore trait, fully decoupling sessions from their storage.
  • An axum Extractor for Session: Applications built with axum can use Session as an extractor directly in their handlers. This makes using sessions as easy as including Session in your handler.
  • Common Backends Out-of-the-Box: RedisStore, SQLx (SqliteStore, PostgresStore, MySqlStore), and MongoDBStore stores are available via their respective feature flags.
  • Layered Caching: With CachingSessionStore, applications can leverage a cache such as MokaStore to reduce roundtrips to the store when loading sessions.
  • Simple Key-Value Interface: Sessions offer a key-value interface that supports native Rust types. So long as these types are Serialize and can be converted to JSON, it's straightforward to insert, get, and remove any value.
  • Strongly-Typed Sessions: Strong typing guarantees are easy to layer on top of this foundational key-value interface.

📦 Install

To use the crate in your project, add the following to your Cargo.toml file:

[dependencies]
tower-sessions = "0.3.1"

🤸 Usage

axum Example

use std::net::SocketAddr;

use axum::{
    error_handling::HandleErrorLayer, response::IntoResponse, routing::get, BoxError, Router,
};
use http::StatusCode;
use serde::{Deserialize, Serialize};
use time::Duration;
use tower::ServiceBuilder;
use tower_sessions::{MemoryStore, Session, SessionManagerLayer};

const COUNTER_KEY: &str = "counter";

#[derive(Default, Deserialize, Serialize)]
struct Counter(usize);

#[tokio::main]
async fn main() {
    let session_store = MemoryStore::default();
    let session_service = ServiceBuilder::new()
        .layer(HandleErrorLayer::new(|_: BoxError| async {
            StatusCode::BAD_REQUEST
        }))
        .layer(
            SessionManagerLayer::new(session_store)
                .with_secure(false)
                .with_max_age(Duration::seconds(10)),
        );

    let app = Router::new()
        .route("/", get(handler))
        .layer(session_service);

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn handler(session: Session) -> impl IntoResponse {
    let counter: Counter = session
        .get(COUNTER_KEY)
        .expect("Could not deserialize.")
        .unwrap_or_default();

    session
        .insert(COUNTER_KEY, counter.0 + 1)
        .expect("Could not serialize.");

    format!("Current count: {}", counter.0)
}

You can find this example as well as other example projects in the example directory.

Note
See the crate documentation for more usage information.

🦺 Safety

This crate uses #![forbid(unsafe_code)] to ensure everything is implemented in 100% safe Rust.

👯 Contributing

We appreciate all kinds of contributions, thank you!

Comments
  • Implement a store that uses Moka

    Implement a store that uses Moka

    This implements a SessionStore that that uses Moka, a high-quality in-process concurrent memory cache. The store takes another SessionStore as an argument when created, which it acts as a wrapper for. It will act as a write-trough cache: when loading a session it will read from the cache and only reach out to the wrapped SessionStore if there is a cache miss. When saving it will put the value both into the cache and push out to the wrapped SessionStore. So essentially it saves a database roundtrip when you load a session, since typically the value will be in the cache. It also intentionally caches negative lookups, to avoid having to hit the database if the same non-existant session id is checked multiple times.

    I also made it possible to use it as a pure memory store, since it only took a couple of extra lines of code to do so.

    opened by and-reas-se 16
  • Clearing a session's data does not get persisted to the store

    Clearing a session's data does not get persisted to the store

    I encountered an issue in 0.2.0 where removing a value from the session would not be considered a change and therefore not saved back into the store.

    This problem only shows when the removed value was the very last one in the session's data, leaving it empty.

    Here is a minimal example of the problem:

    use tower_sessions::Session;
    
    fn main() {
        let session = Session::default();
        assert!(!session.modified());
    
        session.insert("foo", 42);
        assert!(session.modified());
        //      ^^^^^^^^^^^^^^^^^^^ returns `true`, as expected
    
        session.remove_value("foo");
        assert!(session.modified());
        //      ^^^^^^^^^^^^^^^^^^^ suddenly returns `false`, despite the internal `modified` flag being set
    }
    

    Other methods like session.clear() and session.flush() can trigger this issue.

    My use case was that I was removing a user_id field from the session to implement a logout endpoint.
    This issue caused the logout button to effectively do nothing, since the removal wasn't persisted anymore.

    opened by Hirevo 7
  • layered caching for session stores

    layered caching for session stores

    This implements CachingSessionStore, which holds two SessionStores. One acts as a frontend cache, while the other asks as the backend persistence store.

    Anything that implements SessionStore may be used as either the cache or the store.

    We also refactor our Moka implementation as it can now be used for layered caching directly in via CachingSessionStore.

    opened by maxcountryman 7
  • MokaStore, insert into session does not invalidate cached value

    MokaStore, insert into session does not invalidate cached value

    I am using https://github.com/maxcountryman/tower-sessions/blob/main/examples/moka-postgres-store.rs

    Without the moka store, inserting then fetching the value is no problem, everything is updated as it should, however the design of insert must invalidate the cache, right now I tried to use the example and session.insert and later in another route fetching the data gets you the stale cached value.

    opened by beckend 4
  • `std::option_env!(

    `std::option_env!("URL").unwrap()` in tests

    I don't know exactly whether this is a good title for the issue but I'm wondering how you manage to run tests for all databases without the hassle of setting them all up separately.

    opened by avdb13 2
  • `RedisStore` doesn't implement `std::fmt::Debug`

    `RedisStore` doesn't implement `std::fmt::Debug`

    When trying to use a RedisStore inside a CachingSessionStore, it fails, because RedisStore doesn't implement debug.

    Code

    let config = RedisConfig::from_url(&CONFIG.redis_url)?;
    let perf = PerformanceConfig::default();
    let policy = ReconnectPolicy::default();
    let client = RedisClient::new(config, Some(perf), Some(policy));
    
    let redis_conn = client.connect();
    client.wait_for_connect().await?;
    
    let moka_store = MokaStore::new(Some(2000));
    let redis_store = RedisStore::new(client);
    let caching_store = CachingSessionStore::new(moka_store, redis_store);
    
    let session_layer = ServiceBuilder::new()
    	.layer(HandleErrorLayer::new(|_: BoxError| async {
    		StatusCode::BAD_REQUEST
    	}))
    	.layer(
    		SessionManagerLayer::new(caching_store)
    			.with_secure(true)
    			.with_max_age(time::Duration::seconds(10)),
    	);
    

    Error

    error[E0277]: `RedisStore` doesn't implement `std::fmt::Debug`
       --> apps/appealsy-api/src/lib.rs:49:38
        |
    49  |             SessionManagerLayer::new(caching_store)
        |             ------------------------ ^^^^^^^^^^^^^ `RedisStore` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
        |             |
        |             required by a bound introduced by this call
        |
        = help: the trait `std::fmt::Debug` is not implemented for `RedisStore`
        = help: the trait `SessionStore` is implemented for `CachingSessionStore<Cache, Store>`
        = note: required for `CachingSessionStore<MokaStore, RedisStore>` to implement `SessionStore`
    note: required by a bound in `SessionManagerLayer::<Store>::new`
       --> /home/carter/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tower-sessions-0.2.1/src/service.rs:255:13
        |
    255 | impl<Store: SessionStore> SessionManagerLayer<Store> {
        |             ^^^^^^^^^^^^ required by this bound in `SessionManagerLayer::<Store>::new`
    ...
    267 |     pub fn new(session_store: Store) -> Self {
        |            --- required by a bound in this associated function
    
    error[E0599]: the method `with_secure` exists for struct `SessionManagerLayer<CachingSessionStore<MokaStore, RedisStore>>`, but its trait bounds were not satisfied
      --> apps/appealsy-api/src/lib.rs:50:18
       |
    49 | /             SessionManagerLayer::new(caching_store)
    50 | |                 .with_secure(true)
       | |                 -^^^^^^^^^^^ method cannot be called due to unsatisfied trait bounds
       | |_________________|
       | 
       |
      ::: /home/carter/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tower-sessions-0.2.1/src/session_store.rs:59:1
       |
    59 |   pub struct CachingSessionStore<Cache: SessionStore, Store: SessionStore> {
       |   ------------------------------------------------------------------------ doesn't satisfy `_: SessionStore`
       |
       = note: the following trait bounds were not satisfied:
               `CachingSessionStore<MokaStore, RedisStore>: SessionStore`
    
    error[E0277]: `RedisStore` doesn't implement `std::fmt::Debug`
       --> apps/appealsy-api/src/lib.rs:49:13
        |
    49  |             SessionManagerLayer::new(caching_store)
        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `RedisStore` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
        |
        = help: the trait `std::fmt::Debug` is not implemented for `RedisStore`
        = help: the trait `SessionStore` is implemented for `CachingSessionStore<Cache, Store>`
        = note: required for `CachingSessionStore<MokaStore, RedisStore>` to implement `SessionStore`
    note: required by a bound in `SessionManagerLayer`
       --> /home/carter/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tower-sessions-0.2.1/src/service.rs:154:39
        |
    154 | pub struct SessionManagerLayer<Store: SessionStore> {
        |                                       ^^^^^^^^^^^^ required by this bound in `SessionManagerLayer`
    
    opened by Fyko 2
  • Bump fred from 6.3.1 to 6.3.2

    Bump fred from 6.3.1 to 6.3.2

    Bumps fred from 6.3.1 to 6.3.2.

    Release notes

    Sourced from fred's releases.

    6.3.2

    • Fix intermittent disconnections from write errors
    Changelog

    Sourced from fred's changelog.

    6.3.2

    • Fix a bug with connection errors unexpectedly ending the connection task.
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 2
  • track loaded sessions to enable concurrent access

    track loaded sessions to enable concurrent access

    This moves to a pattern of tracking loaded sessions via a hash set. By doing so, we can share sessions concurrently. In other words, we no longer need a lock to protect the session for the duration of the request and instead are able to share sessions between concurrent tasks.

    Why do we need this at all? A data race can otherwise occur when a session has been loaded but its modifications have not been stored. For instance, another task may load the session from the store in the meantime and this load will overwrite pending modifications as it will effectively replace the session in memory.

    One solution to this problem is to lock the request, as we've done in a stopgap capacity. This unscalable at present and even when refined, i.e. to lock per session as opposed for all sessions, limits concurrency over the session itself. In practice, sessions can only be operated on serially and are not available concurrently.

    A more flexible approach is implemented here, allowing for concurrent memory access by limiting loads from the store to situations where no session exists in the loaded set. Put another way, sessions are tracked such that they can be used instead of loading from the store thus ensuring that pending modifications are not lost by a load.

    See #36 for more details about the stopgap locking behavior; this replaces that approach altogether.

    opened by maxcountryman 1
  • fix session saving and loading data race

    fix session saving and loading data race

    This is a temporary fix for a data race that occurs when a session is saved and loaded at the same time. The result of this race is that stale data can be loaded into memory, resulting in potential data loss where multiple requests using the same session are issued simultaneously.

    Here we address this by holding a lock for the duration of the request. This solution is only temporary, as the underlying session implementation can instead be modified to ensure safe access between the save and load await points.

    This supercedes #35.

    opened by maxcountryman 1
  • fix session saving and loading data race

    fix session saving and loading data race

    This fixes a bug where session data could be lost if a session is loaded from the store while it's also being saved back to the store. Because sessions are loaded and stored in memory at the beginning of a request, it was previously possible for a session's inner value to be correctly altered but for that modification to be lost between the moment the session is saved to the store and when it's loaded. In other words, the data loaded would not reflect the in-progress update and instead be stale.

    To address this we could hold a lock for the duration of the request. However, this imposes a performance penalty we would like to avoid. Alternatively we can manage a registry of sessions, a la tower-cookie's management of CookieJar: with this, we load a session first from the service's cache of sessions and fallback to the store only when the session is not present.

    Currently sessions are managed like this via DashMap. However, alternatively caching facilities, such as Moka, might prove to be a better fit. Further, the current implementation does not bound the total number of cached sessions--this should be addressed in future updates. At present, this means memory will continue to grow, albeit typically at a very small rate; this is a memory leak!

    Because sessions are safely written to and read from this cache, we prevent stale reads and thus a data race which could lead to data loss in highly concurrent environments, especially where multiple requests are made using the same session cookie simultaneously.

    Note that replace_if_equal is still required to prevent data races in application code.

    opened by maxcountryman 1
  • Update fred requirement from 6.3.2 to 7.0.0

    Update fred requirement from 6.3.2 to 7.0.0

    Updates the requirements on fred to permit the latest version.

    Release notes

    Sourced from fred's releases.

    7.0.0

    • Added a new client Builder and configuration interface.
    • Reworked or removed the majority of the globals interface.
    • Support multiple IP addresses in the Resolve interface.
    • Add with_options command configuration interface.
    • Replaced the no-client-setname feature flag with auto-client-setname.
    • Add an interface to configure TCP socket options.
    • Removed the automatic serde_json::Value -> RedisValue type conversion logic.
    • Reworked the majority of the RedisPool interface.
    • Moved and refactored the on_* functions into a new EventInterface.
    • Fixed bugs with the Replica routing implementation.
    • Fixed bugs related to parsing single-element arrays.
    • Changed several FromRedis type conversion rules.
    • Add a RedisJSON interface.
    • Add a RESP2 and RESP3 codec interface.
    Changelog

    Sourced from fred's changelog.

    7.0.0

    • Added a new client builder and configuration interface.
    • Reworked or removed the majority of the globals interface.
    • Support multiple IP addresses in the Resolve interface.
    • Add with_options command configuration interface.
    • Replaced the no-client-setname feature flag with auto-client-setname.
    • Add an interface to configure TCP socket options.
    • Removed the automatic serde_json::Value -> RedisValue type conversion logic.
      • This unintentionally introduced some ambiguity on certain interfaces.
      • The RedisValue -> serde_json::Value type conversion logic was not changed.
    • Reworked the majority of the RedisPool interface.
    • Moved and refactored the on_* functions into a new EventInterface.
    • Fixed bugs with the Replica routing implementation.
    • Fixed bugs related to parsing single-element arrays.
    • Changed several FromRedis type conversion rules. See below or the FromRedis docs for more information.
    • Add a RedisJSON interface.
    • Add a RESP2 and RESP3 codec interface.

    Upgrading from 6.x

    Notable interface changes:

    • ArcStr has been replaced with bytes_utils::Str.
    • Timeout arguments or fields now all use std::time::Duration.
    • Many of the old global or performance config values can now be set on individual commands via the with_options interface.
    • The RedisPool interface now directly implements ClientLike rather than relying on Deref shenanigans.
    • The on_* event functions were moved and renamed. Reconnection events now include the associated Server.
    • The tls_server_name field on Server is now properly gated by the TLS feature flags.
    • Mocks are now optional even when the feature flag is enabled.

    Notable implementation Changes:

    • Pipeline and Transaction structs can now be reused. Calling exec, all, last, or try_all no longer drains the inner command buffer.
    • Many of the default timeout values have been lowered significantly, often from 60 sec to 10 sec.
    • In earlier versions the FromRedis trait implemented a few inconsistent or ambiguous type conversions policies.
      • Most of these were consolidated under the default-nil-types feature flag.
      • It is recommended that callers review the updated FromRedis docs or see the unit tests in responses.
    • The connect function can now be called more than once to force reset all client state.

    6.3.2

    • Fix a bug with connection errors unexpectedly ending the connection task.

    6.3.1

    • Update various dependencies
    • Move pretty-env-logger to dev-dependencies
    • Update rustfmt.toml

    ... (truncated)

    Commits

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies rust 
    opened by dependabot[bot] 1
  • Support custom schema names

    Support custom schema names

    Right now the schema_name for the SQLX stores is hardcoded to be "tower_sessions", ignoring the database specified in the database URL.

    My current Docker setup creates a user with access to only one database. It would be useful to to be able to have it use that specific database.

    enhancement help wanted good first issue 
    opened by Hellrespawn 4
  • Support `diesel` as database library

    Support `diesel` as database library

    Tower-sessions offers various sessions storages backed by relational databases. It only supports sqlx based connections for these stores. It would be great to allow other database connection types like that one provided by diesel/diesel-async as well, as users might prefer these for various reasons.

    help wanted good first issue 
    opened by weiznich 1
Releases(v0.3.1)
  • v0.3.1(Oct 11, 2023)

    What's Changed

    • Use DashMap entry API to address data race introduced by dashmap. #41

    Full Changelog: https://github.com/maxcountryman/tower-sessions/compare/v0.3.0...v0.3.1

    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Oct 10, 2023)

    What's Changed

    Breaking Changes

    • tokio feature flag is now tokio-rt.
    • Session IDs are returned as references now.

    Other Changes

    • Update fred to 7.0.0.
    • Track loaded sessions to enable concurrent access. #37

    Full Changelog: https://github.com/maxcountryman/tower-sessions/compare/v0.2.4...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.4(Oct 9, 2023)

    What's Changed

    • Fix session saving and loading data race. https://github.com/maxcountryman/tower-sessions/pull/36

    Full Changelog: https://github.com/maxcountryman/tower-sessions/compare/v0.2.3...v0.2.4

    Source code(tar.gz)
    Source code(zip)
  • v0.2.3(Oct 8, 2023)

    What's Changed

    • Fix setting of modified in replace_if_equal.

    Full Changelog: https://github.com/maxcountryman/tower-sessions/compare/v0.2.2...v0.2.3

    Source code(tar.gz)
    Source code(zip)
  • v0.2.2(Oct 8, 2023)

    What's Changed

    • Lift Debug constraint on CachingSessionStore.
    • Run caching store save and load ops concurrently. #25

    Full Changelog: https://github.com/maxcountryman/tower-sessions/compare/v0.2.1...v0.2.2

    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Oct 2, 2023)

    What's Changed

    • Fix clearing session's data is not persisted. #22

    Full Changelog: https://github.com/maxcountryman/tower-sessions/compare/v0.2.0...v0.2.1

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Oct 1, 2023)

    What's Changed

    Breaking Changes

    • Renamed store error variants for consistency (SqlxStoreError, RedisStoreError). #18
    • Moved MySQL expiration_time column to `timestamp(6), for microsecond resolution. #14
    • Replaced Session.with_max_age with set_expiration_time and set_expiration_time_from_max_age, allowing applications to control session durations dynamically. #7

    Other changes

    • Provide layered caching via CachingSessionStore #8
    • Provide a Moka store #6 (Thank you @and-reas-se!)
    • Provide a MongoDB store #5 (Thank you @JustMangoT!)

    New Contributors

    • @and-reas-se made their first contribution in https://github.com/maxcountryman/tower-sessions/pull/6
    • @JustMangoT made their first contribution in https://github.com/maxcountryman/tower-sessions/pull/5
    • @beckend made their first contribution in https://github.com/maxcountryman/tower-sessions/pull/19

    Full Changelog: https://github.com/maxcountryman/tower-sessions/compare/v0.1.0...v0.2.0

    Source code(tar.gz)
    Source code(zip)
Owner
Max Countryman
People first leader and indie hacker.
Max Countryman
A cookie manager middleware built on top of tower.

tower-cookies A cookie manager middleware built on top of tower. Example With axum: use axum::{handler::get, Router}; use std::net::SocketAddr; use to

Imbolc 47 Dec 9, 2022
A crate built on top of `axum-sessions`, implementing the CSRF Synchronizer Token Pattern

Axum Synchronizer Token Pattern CSRF prevention This crate provides a Cross-Site Request Forgery protection layer and middleware for use with the axum

null 3 Dec 15, 2022
🔎 Prometheus metrics middleware for Axum

Axum-Prometheus A Prometheus middleware to collect HTTP metrics for Axum applications. axum-prometheus relies on metrics_exporter_prometheus as a back

Péter Leéh 14 Jan 4, 2023
Axum + JWT authentication Middleware that allows you to start building your application fast

axum_jwt_ware Integration Guide Simple Axum + JWT authentication middleware with implemented Login and refresh token. Goal I aim to simplify the proce

Eze Sunday 3 Dec 2, 2023
axum-serde is a library that provides multiple serde-based extractors and responders for the Axum web framework.

axum-serde ?? Overview axum-serde is a library that provides multiple serde-based extractors / responses for the Axum web framework. It also offers a

GengTeng 3 Dec 12, 2023
Ergonomic and modular web framework built with Tokio, Tower, and Hyper

axum axum is a web application framework that focuses on ergonomics and modularity. More information about this crate can be found in the crate docume

Tokio 7.9k Dec 31, 2022
Rate limit middleware for Poem framework

Rate limit middleware for Poem framework Usage Check examples, poem-ratelimit is available on crates.io. A yaml configuration file is used to set limi

Devs Day 5 Sep 22, 2022
Write Rack middleware in Rust.

RacksOnRacks Write Rack middleware in Rust. This repo is a proof of concept and should be used as an example. The best way to use this at the moment w

Odin 5 Jul 11, 2023
Demo of Rust and axum web framework

Demo of Rust and axum web framework Demonstration of: Rust: programming language that focuses on reliability and stability. axum: web framework that f

Joel Parker Henderson 115 Dec 29, 2022
Layers, extractors and template engine wrappers for axum based Web MVC applications

axum-template Layers, extractors and template engine wrappers for axum based Web MVC applications Getting started Cargo.toml [dependencies] axum-templ

Altair Bueno 11 Dec 15, 2022
Simple example of axum, sqlx with sqlite and utoipa (swagger) - without auth

axum_crud_api Simple example to learn creating CRUD rest apis in Rust with axum, sqlx with sqlite and utoipa (swagger) - without auth Also shows how t

null 2 Nov 12, 2022
Heavy Metal Leptos Stack with Tailwind, Axum, Sqlite, and Cargo Leptos

Heavy Metal Stack Leptos stack with Axum, TailwindCSS, and Sqlite This example creates a basic todo app with an Axum backend that uses Leptos' server

Ben Wishovich 7 Dec 31, 2022
Starter template for use with the Leptos web framework and Axum.

Leptos Axum Starter Template This is a template for use with the Leptos web framework and the cargo-leptos tool using Axum. Creating your template rep

Leptos 10 Mar 4, 2023
Rust server with Axum, GraphQL and SurrealDb

??️ Article on my web Axum server, Async-GraphQl, SurrealDB template Run without any prior setup, DB is in memory: cargo run To use routes other than

null 15 Jun 26, 2023
Leptos Axum Prisma starter with Admin dashboard and SSR/SPA website

LAPA - Leptos Axum Prisma starter with Admin dashboard and SSR/SPA website Motivation I want to have practical full-stack setup to build websites and

Alexi Chepura 2 Jul 10, 2023
Htmx extractors and request guards for axum.

axum-htmx axum-htmx is a small extension library providing extractors and request guards for the various htmx headers within axum. Additionally, the l

Rob 5 Aug 14, 2023
Experiments with Rust CRDTs using Tokio web application framework Axum.

crdt-genome Synopsis Experiments with Rust CRDTs using Tokio web application framework Axum. Background Exploring some ideas of Martin Kleppmann, part

dougfort 3 Mar 18, 2022
Axum web framework tutorial for beginners.

Axum Tutorial For Beginners Hello web developers! This tutorial will cover how to write simple web applications in rust with axum framework. If you ar

Eray Karatay 46 Jan 5, 2023
Yew + Axum + blog = Yab

Yew + Axum + blog = Yab

STUDIO RSBM 13 Dec 5, 2022