Code Monkey home page Code Monkey logo

pavex's Introduction

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.

Pavex takes a significantly different approach compared to the current generation of Rust web frameworks: you can think of Pavex as a specialised compiler for building Rust APIs.
It takes as input a high-level description of what your application should do, a Blueprint:

pub fn app_blueprint() -> Blueprint {
    let mut bp = Blueprint::new();
    bp.constructor(f!(crate::http_client), Lifecycle::Singleton);
    bp.constructor(f!(crate::extract_path), Lifecycle::RequestScoped);
    bp.constructor(f!(crate::logger), Lifecycle::Transient);
    bp.route(GET, "/home", f!(crate::stream_file));
    bp
}

It generates as output a standalone API server SDK crate, behaving according to your specification, ready to be configured and launched.

Great error messages

Pavex operates at the right level of abstraction—it understands the specific challenges and requirements of API development.
The intermediate code generation step (Blueprint -> runtime code) allows Pavex to perform in-depth static analysis. Potential issues are caught at compile-time with an informative error message:

ERROR:
  × `app::get_home` is trying to extract route parameters using `RouteParams<HomeRouteParams>`.
  │ Every struct field in `app::HomeRouteParams` must be named after one of the route parameters 
  | that appear in `/address/:address_id/home/:home_id`:
  │ - `home_id`
  │ - `address_id`
  │
  │ There is no route parameter named `street_id`, but there is a struct field named
  │ `street_id` in `app::HomeRouteParams`. This is going to cause a runtime error!
  │
  │     ╭─[src/lib.rs:43:1]
  │  43 │     ));
  │  44 │     bp.route(GET, "/home/:id", f!(crate::get_home));
  │     ·                                ───────────┬──────
  │     ·             The request handler asking for `RouteParams<app::HomeRouteParams>`
  │  45 │     
  │     ╰────
  │   help: Remove or rename the fields that do not map to a valid route parameter.

Compile-time dependency injection

Your Blueprint tells Pavex:

  • What routes should be exposed;
  • What components can be built, what inputs they need and what is their lifecycle;
  • How to handle errors.

Pavex uses this information to perform compile-time dependency injection.

Each endpoint gets its own call graph and Pavex makes sure to exclusively build what is required to invoke every single endpoint, avoiding unnecessary computations.

flowchart TB
    handler["app::stream_file(Pathbuf, Logger, &Client)"]
    client[Client]
    logger["logger() -> Logger"]
    state[ServerState]
    path["extract_path(&RequestHead)->PathBuf"]
    request[RequestHead]

    state --> client
    client --&--> handler
    logger --> handler
    path --> handler
    request --&--> path

You write straight-forward Rust, Pavex takes care of assembling together all the components.

Project status

Pavex is under active development and far from being ready for hobby or production usage.
It has not yet been released on crates.io and you can expect breaking changes on every commit to the main branch.

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

We regularly publish project updates:

Examples

You can see Pavex at work in the /examples folder:

In examples/skeleton/blueprint.ron you can have a peek at what the Blueprint looks like when serialized.

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

This project is not open to unsolicited code contributions (for the time being).
If you want to play around with it, you can find 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 dependabot[bot] avatar kingdutch avatar lukemathwalker avatar m1guelpf 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  avatar  avatar  avatar  avatar

pavex's Issues

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: m1guelpf/pavex_clone_panic_repro@f4b5abc. 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,

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

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.

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: m1guelpf/pavex_unreachable_repro@8de12d1

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.