Giter VIP home page Giter VIP logo

pavex's Introduction

pavex pavex
Re-imagining backend development in Rust

What is Pavex?

Pavex is a new framework to build APIs with Rust.

Pavex aims to have it all: great ergonomics and high performance.
The same productivity boost of Ruby on Rails, Spring or ASP.NET Core.
As fast as a handwritten solution that strips away all abstractions.

Check out Pavex's documentation for a thorough introduction to the framework and its design philosophy.

Project status

Pavex is currently in closed beta—you can sign up here to get early access.

We regularly publish project updates.

Last update: This month in Pavex #10 [April 2024]

Previous updates:

Architectural Overview

If the section above was enough to get you intrigued, you can check out the architectural deep-dive in ARCHITECTURE.md to learn how Pavex works under the hood.

Contributing

Typo in documentation? Open a PR straight-away!
Small bug fix with a regression test? Open a PR straight-away!
Anything beyond 20 lines of code? Open an issue first.

If you are looking to contribute, you can find dedicated instructions in CONTRIBUTING.md.

License

Licensed under the Apache License, Version 2.0. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions.

pavex's People

Contributors

autarch avatar benwis avatar bobby-wan avatar bosukas avatar darkkeh avatar dependabot[bot] avatar etiescu avatar github-actions[bot] avatar hlbarber avatar jehrhardt avatar kingdutch avatar lukemathwalker avatar m1guelpf avatar nvzqz avatar pavex-releaser[bot] avatar sondrelg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pavex's Issues

Panic when generating SDK with clones

Here's the setup for this error:

  • A non-Clone struct (SharedDep), which gets wrapped in an Arc and registered as a singleton.
  • A second Clone struct (MiddlewareDep), which receives SharedDep as a dependency, and is request-scoped.
  • A middleware that receives MiddlewareDep as a dependency.
  • A route, which is both wrapped by the middleware and also receives SharedDep

When building the sdk, this produces the following panic:

thread 'main' panicked at pavexc/src/compiler/analyses/call_graph/application_state.rs:130:13:
One of the output components is not a `MatchResult` transformer: Transformer(Callable(<alloc::sync::Arc::<arc_repro::SharedDep> as core::clone::Clone>::clone(&alloc::sync::Arc<arc_repro::SharedDep>) -> alloc::sync::Arc<arc_repro::SharedDep>))

Here's a 30-line commit reproducing this over the default Pavex template: https://github.com/m1guelpf/pavex_clone_panic_repro/commit/8de12d1895ff5013c7e7304319697709529ddcd3

feat: Improve docs: UI, Features, Extensibility

This is just a proposal to move over to Nextra for documentation as full MDX gives a lot more flexibility in terms of embedding demos, custom components, and more in the future but also it provides a far nicer experience for navigating around the docs along with a cleaner overall UI.

UI Comparrison

image

Improved ease of editing

Allow community discovered issues to be patched and fixed in a minute or two with a quick PR by linking directly to source files

Screenshot 2024-05-13 at 1 22 17 AM

Subpage Linking

Support for linking to page sections like /guide/cookies/response_cookies#remove-a-client-side-cookie inside of longer pages when sharing or searching for documentation.

image

Maintenance Improvements

  • Complete removal of doc_examples folder and it's sprawl of dozens of *.snap files per section
  • Direct control over custom components rather than reliance on Material for MkDocs.

Also the side bar is much nicer for finding things, Material MkDocs is kind of a pain to navigate around you can't see upper or lower folder levels when on medium width screens or doing split tabs

Other note, I'm completely willing to port this over I just decided to try out a simple port since navigating around the docs to learn more about the framework was frustratingly difficult while trying to have anything else open

mdBook include directive vs `tutorial_generator`

I read the newsletter https://www.lpalmieri.com/posts/this-month-in-pavex-08/ and saw https://github.com/LukeMathWalker/pavex/blob/main/doc_examples/quickstart/tutorial.yml , and I wondered if mdBook has been considered over mkdocs?

mdBook can include portions of a file: https://rust-lang.github.io/mdBook/format/mdbook.html?#including-portions-of-a-file which means, that code can live separate from the actual documentation and can be tested as such. Also, mdbook test can test rust code examples embedded in Markdown.

So what I wondered reading the blog post, has mdBook been considered and if so, what was the reasoning to decide against it? I'm interested in it, solely for my own research purposes.

Pavex documentation on rustdoc json

The Pavex docs do not mention how to install the Rust core packages docs as JSON.

Running cargo px build gave the following error:

ERROR: 
  × I failed to compute the JSON documentation for one or more crates in the workspace.
  │

Error: `pavex_cli` exited with a non-zero status code: 1
error: Failed to run `bp`, the code generator for package `api_server_sdk`

Fixed by running rustup component add --toolchain nightly rust-docs-json

Credit to Alona for writing about this here: https://alona.page/posts/rustdoc-json-2022/#:~:text=Making%20this%20work,toolchain%20by%20rustup

Middleware in nested Blueprint reaches unreachable code

When playing around with my Router, I started reaching an unreachable!() spot. Very conveniently, it's not an issue with my very weird code but something that can be replicated in a few lines over the starter kit: https://github.com/m1guelpf/pavex_unreachable_repro/commit/e153691aa9afd1a7885b8f84224c3b71147818a6

thread 'main' panicked at pavexc/src/compiler/analyses/processing_pipeline/codegen.rs:82:25:
internal error: entered unreachable code

Mislabeled exception when unable to resolve dependency graph

I was very confused when I got this error pointing to the default route that comes with the template.

ERROR: 
  x I don't know how to handle the type returned by `app::routes::system::health_check`.
  |
  |     ,-[app/src/routes/mod.rs:10:1]
  |  10 | pub fn handler(bp: &mut Blueprint) {
  |  11 |     bp.route(GET, "/healthz", f!(crate::routes::system::health_check));
  |     :                               ^^^^^^^^^^^^^^^^^^^|^^^^^^^^^^^^^^^^^^^
  |     :                                                  `-- The request handler was registered here
  |  12 | }
  |     `----
  |    ,-[app/src/routes/system.rs:4:1]
  |  4 | #[must_use]
  |  5 | pub const fn health_check() -> StatusCode {
  |    :                                ^^^^^|^^^^
  |    :                                     `-- The output type that I can't handle
  |  6 |     StatusCode::OK
  |    `----

Turns out, the error triggers when you try to import a crate which uses a different version of a dependency your app crate also requires. I've created an example repo with two commits. The first one does not compile with the above error, while mirroring the features on the app crate compiles without issues.

feat: bazel (and/or other build system) rulesets

Most of the time Bazel users generate a ruleset outside of the project the ruleset is for. Exceptions include a) things like GRPC that are natively maintained using Bazel, and b) developer orientated products where the user interface is one of their concerns.

Pavex seems to fall into (b) - and because you've got a big focus on the developer experience, extending that out into users of Bazel, nix, pants2, buck2 and other related build systems will likely be relevant/important.

Because pavex is doing code generation, it -is- going to interact with those systems, as sqlx does (e.g. launchbadge/sqlx#2927 ), and anything outside OSS sphere is IME increasingly likely to use such a system.

Axum & Pavex

Hello,
I was wondering: what's the point of using Pavex compared to Axum, when one can just use Axum?
What significant advantages does Pavex have?

Automatic openapi generation

As pavex is a compiler, it would be cool to explore the possibilities of generating openapi specs for the blueprint.

I understand that this might not be that high on the list of features at the moment, but I think it is one of the biggest pain points when creating APIs, and I would love to see pavex's take on it.

Closed beta / Apache license

I hope this is not a silly question, but what is the meaning of the project being in "closed beta" when it appears to be available here under a Apache V2 License?

Codegen Panic: pre-processor middleware w/mutable dependency injection

I tried this code: repo

Registered a constructor & fallible pre-processor middleware: link

pub fn tickets_bp() -> Blueprint {
    let mut bp = Blueprint::new();

    bp.request_scoped(f!(crate::tickets::TicketForCreate::extract))
        .error_handler(f!(crate::tickets::invalid_ticket));
    
    bp.request_scoped(f!(crate::ctx::Ctx::new));

    bp.pre_process(f!(super::web::mw_auth::mw_require_auth))
        .error_handler(f!(super::web::mw_auth::mw_auth_error));

    bp.route(POST, "/tickets", f!(self::tickets::post));
    bp.route(GET, "/tickets", f!(self::tickets::get));
    bp.route(DELETE, "/tickets/:id", f!(self::tickets::delete));
    bp
}

Passed a mutable reference to the middleware (note: this works): link

pub async fn mw_require_auth(request_cookies: RequestCookies<'_>, ctx: &mut Ctx) -> Result<Processing, AuthError> {
    [...]
    ctx.set(user_id);

    tracing::Span::current().record("auth_status", "success");
    Ok(Processing::Continue)
}

Access the context in a subsequent hander (note: this breaks):

pub async fn get(mc: &ModelController, ctx: Ctx) -> Response {
    let tickets = mc.list_tickets(ctx).await;
    [...]
}
    pub async fn list_tickets(&self, _ctx: Ctx) -> Result<Vec<Ticket>, TicketError> {
        let store = self.tickets_store.lock().await;
        let tickets = store.iter().filter_map(|t| t.clone()).collect();
        Ok(tickets)
    }

I expected to see this happen:
I expected no change in the tests/running of the example since the context isn't used in the downstream handler logic.

Instead, this happened:
Application fails to build and panics during codegen.

Error

cargo px check:

   Computing package graph
    Computed package graph in 0.102s
   Compiling `bp`, the code generator for `server_sdk`
warning: /home/snarkipus/Projects/rust-edu/Pavex/chone/workspace_hack/Cargo.toml: no edition set: defaulting to the 2015 edition while the latest is 2021
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.05s
    Compiled `bp`, the code generator for `server_sdk`, in 0.062s
  Generating `server_sdk`
warning: /home/snarkipus/Projects/rust-edu/Pavex/chone/workspace_hack/Cargo.toml: no edition set: defaulting to the 2015 edition while the latest is 2021
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.05s
     Running `target/debug/bp`

Backtrace omitted. Run with RUST_BACKTRACE=1 to display it.
Run with RUST_BACKTRACE=full to include source snippets.

The application panicked (crashed).
  Could not find a binding for input type `app::ctx::Ctx` in the input bindings.
  Input bindings: 
  - s_0: &pavex::request::RequestHead, 
  - s_1: &biscotti::Processor, 
  - s_2: &app::configuration::ModelController, 
  - s_3: pavex::request::path::MatchedPathPattern, 
in pavexc/src/compiler/analyses/processing_pipeline/codegen.rs, line 108
thread: main
The invocation of `pavex [...] generate [...]` exited with a non-zero status code: 101
error: Failed to run `bp`, the code generator for package `server_sdk`

Meta

pavex --version:

pavex_cli 0.1.44 (13ff1e0)

rustc --version --verbose:

rustc 1.81.0-nightly (ba1d7f4a0 2024-06-29)
binary: rustc
commit-hash: ba1d7f4a083e6402679105115ded645512a7aea8
commit-date: 2024-06-29
host: x86_64-unknown-linux-gnu
release: 1.81.0-nightly
LLVM version: 18.1.7
Backtrace

Backtrace (most recent call first):
  File "<unknown>", line 0, in pavexc::compiler::analyses::processing_pipeline::codegen::<impl pavexc::compiler::analyses::processing_pipeline::pipeline::RequestHandlerPipeline>::codegen
  File "<unknown>", line 0, in <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter
  File "<unknown>", line 0, in <alloc::collections::btree::map::BTreeMap<K,V> as core::iter::traits::collect::FromIterator<(K,V)>>::from_iter
  File "<unknown>", line 0, in pavexc::compiler::codegen::codegen_app
  File "<unknown>", line 0, in pavexc::compiler::app::App::codegen
  File "<unknown>", line 0, in pavexc::main
  File "<unknown>", line 0, in std::sys_common::backtrace::__rust_begin_short_backtrace
  File "<unknown>", line 0, in std::rt::lang_start::{{closure}}
  File "<unknown>", line 0, in std::rt::lang_start_internal
  File "<unknown>", line 0, in main
  File "./csu/../sysdeps/nptl/libc_start_call_main.h", line 58, in __libc_start_call_main
  File "./csu/../csu/libc-start.c", line 360, in __libc_start_main_impl
  File "<unknown>", line 0, in _start

Not sure if it helps, but I can see the following in the codegen output:

Pre-processing codegen picks it up the context: link

    async fn pre_processing_0(
        v0: &biscotti::Processor,
        v1: &pavex::request::RequestHead,
    ) -> pavex::middleware::Processing {
        [....]
        let mut v4 = app::ctx::Ctx::new();
        let v5 = app::routes::web::mw_auth::mw_require_auth(v3, &mut v4).await;
        [....]
    }

Handler codegen does not (error): link

    async fn handler(
        v0: &app::configuration::ModelController,
        // assuming missing input parameter `vX: &app::ctx::Ctx`
    ) -> pavex::response::Response {
        let v1 = app::routes::web::tickets::get(v0).await; // <--- missing argument for `vX` of type ctx: Ctx
        <pavex::response::Response as pavex::response::IntoResponse>::into_response(v1)
    }

Cannot register a singleton wrapped in `Arc<_>`

Use-case

In order to register a Singleton, the base type must implement Clone. To prevent unnecessary cloning, it makes sense to use a pointer instead.

Repro

I've created a new repo with a single commit on top of the base pavex new installation, showcasing the issue: https://github.com/m1guelpf/pavex_arc_repro/commit/f4b5abc51b8f166a24ff5523da15a1b1420847ed. Running cargo px run on the root of this repo fails with the following error:

error[E0433]: failed to resolve: use of undeclared crate or module `alloc`
  --> arc_repro_server_sdk/src/lib.rs:97:13
   |
97 |         v1: alloc::sync::Arc<arc_repro::ExampleDependency>,
   |             ^^^^^ use of undeclared crate or module `alloc`
   |
   = help: add `extern crate alloc` to use the `alloc` crate
help: consider importing one of these items
   |
95 +     use crate::alloc::sync;
   |
95 +     use std::sync;
   |
help: if you import `sync`, refer to it directly
   |
97 -         v1: alloc::sync::Arc<arc_repro::ExampleDependency>,
97 +         v1: sync::Arc<arc_repro::ExampleDependency>,
   |

error[E0433]: failed to resolve: use of undeclared crate or module `alloc`
   --> arc_repro_server_sdk/src/lib.rs:109:13
    |
109 |         v0: alloc::sync::Arc<arc_repro::ExampleDependency>,
    |             ^^^^^ use of undeclared crate or module `alloc`
    |
    = help: add `extern crate alloc` to use the `alloc` crate
help: consider importing one of these items
    |
95  +     use crate::alloc::sync;
    |
95  +     use std::sync;
    |
help: if you import `sync`, refer to it directly
    |
109 -         v0: alloc::sync::Arc<arc_repro::ExampleDependency>,
109 +         v0: sync::Arc<arc_repro::ExampleDependency>,
    |

error[E0433]: failed to resolve: use of undeclared crate or module `alloc`
   --> arc_repro_server_sdk/src/lib.rs:118:14
    |
118 |         s_0: alloc::sync::Arc<arc_repro::ExampleDependency>,
    |              ^^^^^ use of undeclared crate or module `alloc`
    |
    = help: add `extern crate alloc` to use the `alloc` crate
help: consider importing one of these items
    |
95  +     use crate::alloc::sync;
    |
95  +     use std::sync;
    |
help: if you import `sync`, refer to it directly
    |
118 -         s_0: alloc::sync::Arc<arc_repro::ExampleDependency>,
118 +         s_0: sync::Arc<arc_repro::ExampleDependency>,
    |

error[E0433]: failed to resolve: use of undeclared crate or module `alloc`
   --> arc_repro_server_sdk/src/lib.rs:119:18
    |
119 |         next: fn(alloc::sync::Arc<arc_repro::ExampleDependency>) -> T,
    |                  ^^^^^ use of undeclared crate or module `alloc`
    |
    = help: add `extern crate alloc` to use the `alloc` crate
help: consider importing one of these items
    |
95  +     use crate::alloc::sync;
    |
95  +     use std::sync;
    |
help: if you import `sync`, refer to it directly
    |
119 -         next: fn(alloc::sync::Arc<arc_repro::ExampleDependency>) -> T,
119 +         next: fn(sync::Arc<arc_repro::ExampleDependency>) -> T,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.