Crate rupring

Source
Expand description

§Get Started

There is only one dependency.

cargo add rupring

And you can write your server like this:

#[derive(Debug, Clone, Copy)]
#[rupring::Module(controllers=[HomeController{}], modules=[])]
pub struct RootModule {}

#[derive(Debug, Clone)]
#[rupring::Controller(prefix=/, routes=[hello, echo])]
pub struct HomeController {}

#[rupring::Get(path = /)]
pub fn hello(_request: rupring::Request) -> rupring::Response {
    rupring::Response::new().text("Hello, World!".to_string())
}

#[rupring::Get(path = /echo)]
pub fn echo(request: rupring::Request) -> rupring::Response {
    rupring::Response::new().text(request.body)
}

fn main() {
    rupring::run(RootModule {})
}

§Request

  • rupring defines HTTP Request through crate::request::Request type and provides convenient request processing using macros.
#[rupring::Get(path = /:id)]
pub fn hello(request: rupring::Request) -> rupring::Response {
    let method = request.method;
    assert_eq!(method, rupring::Method::GET);

    let path = request.path;
    assert_eq!(path, "/");

    let body = request.body;
    assert_eq!(body, "");

    let headers = request.headers;
    let content_type = headers.get("content-type").unwrap();
    assert_eq!(content_type, "text/plain");

    let id = request.path_parameters["id"].clone();
    assert_eq!(id, "123");

    let query = request.query_parameters["query"].clone();
    assert_eq!(query, vec!["asdf".to_string()]);

    //...

    response
}
  • Please refer to the corresponding document for more details.

§Response

  • rupring defines HTTP Response through crate::response::Response type and provides convenient response processing using macros.
#[rupring::Get(path = /)]
pub fn hello(_request: rupring::Request) -> rupring::Response {
    rupring::Response::new().text("Hello, World!".to_string())
}
  • Please refer to the corresponding document for more details.

§Middleware

rupring provides middleware features for common logic processing.

If you want to log requests for all APIs that exist in a module, you can apply middleware in the form below.

First, define a middleware function.

pub fn logger_middleware(
    request: rupring::Request,
    response: rupring::Response,
    next: rupring::NextFunction,
) -> rupring::Response {
    println!(
        "Request: {} {}",
        request.method.to_string(),
        request.path.to_string()
    );

    next(request, response)
}

The above function only records logs and forwards them to the next middleware or route function. If you want to return a response immediately without forwarding, just return the response without calling the next function.

And you can register the middleware function just defined in the module or controller unit.

pub fn logger_middleware(
    request: rupring::Request,
    response: rupring::Response,
    next: rupring::NextFunction,
) -> rupring::Response {
    println!(
        "Request: {} {}",
        request.method.to_string(),
        request.path.to_string()
    );

    next(request, response)
}

#[derive(Debug, Clone, Copy)]
#[rupring::Module(
    controllers=[RootController{}],
    modules=[UserModule{}],
    providers=[],
    middlewares=[logger_middleware]
)]
pub struct RootModule {}

#[derive(Debug, Clone)]
#[rupring::Controller(prefix=/, routes=[])]
pub struct RootController {}

#[derive(Debug, Clone, Copy)]
#[rupring::Module(
    controllers=[UserController{}],
    providers=[],
    middlewares=[]
)]
pub struct UserModule {}

// or Controller
#[derive(Debug, Clone)]
#[rupring::Controller(prefix=/, routes=[], middlewares=[logger_middleware])]
pub struct UserController {}

Middleware registered in a module is recursively applied to the routes of controllers registered in that module and to child modules. On the other hand, middleware registered in a controller applies only to the routes of that controller.

The priorities in which middleware is applied are as follows:

  1. Middleware of the same unit is executed in the order defined in the array.
  2. If module middleware and controller middleware exist at the same time, module middleware is executed first.
  3. If the parent module’s middleware and the child module’s middleware exist at the same time, the parent module middleware is executed first.

§Dependency Injection

  • Rupring provides powerful DI features through macro and runtime support.
#[derive(Debug, Clone, Default)]
pub struct HomeService {}

impl HomeService {
    pub fn hello(&self) -> String {
        "hello!!".to_string()
    }
}

impl rupring::IProvider for HomeService {
    fn provide(&self, di_context: &rupring::DIContext) -> Box<dyn std::any::Any> {
        Box::new(HomeService {})
    }
}
  • Please refer to the corresponding document for more details.

§Swagger

  • When rupring starts the server, it automatically serves swagger documents to the /docs path.
  • Please refer to the corresponding document for more details.

§Application Properties

  • rupring provides various execution options through a special configuration file called application.properties.
  • Please refer to the corresponding document for more details.

§AWS Lambda

  • rupring provides the option to run on AWS Lambda.
  • Supported Lambda Runtimes
    1. Amazon Linux 2
    2. Amazon Linux 2023

§How to use

  1. Enable the “aws-lambda” feature flag.
rupring={ version = "0.12.0", features=["aws-lambda"] }
  1. Use the rupring::run_on_aws_lambda function instead of rupring::run.
fn main() {
    rupring::run_on_aws_lambda(RootModule {})
}
  1. Compile and create an executable file. (x86_64-unknown-linux-musl)
rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl
  1. Zip the executable file and upload it to the AWS console.
  • The name of the executable file must be bootstrap.
zip -j bootstrap.zip ./target/x86_64-unknown-linux-musl/release/bootstrap
  1. …and upload it as a file to the AWS console

Re-exports§

pub use di::DIContext;
pub use di::IProvider;
pub use request::ParamString;
pub use request::ParamStringDeserializer;
pub use request::Request;
pub use response::Response;
pub use anyhow;
pub use serde_json;
pub use tokio;

Modules§

application_properties
Application Properties
di
Dependency Injection
header
header constants
meme
MEME type constants
request
HTTP request module
response
HTTP response module
swagger
swagger module

Macros§

error
Construct an ad-hoc error from a string or existing non-anyhow error value.

Structs§

RupringFactory
Rupring Factory for creating server

Traits§

IController
Controller interface
IHandler
Handler interface
IModule
Module interface
IRoute
Route interface

Functions§

run
shortcut to run the application

Type Aliases§

HeaderName
HTTP Header Name (from hyper crate)
Method
HTTP method (from hyper crate)
MiddlewareFunction
Middleware function type
NextFunction
Next function type for middleware
Result
Result<T, Error>

Attribute Macros§

Bean
This is an alias for Injectable.
Component
This is an alias for Injectable.
Controller
Controller Annotation
Delete
Delete Route Annotation
DeleteMapping
This is an alias for Delete.
Get
Get Route Annotation
GetMapping
This is an alias for Get.
Injectable
This is a shortcut annotation for creating an IProvider object.
Module
Module Annotation
Patch
Patch Route Annotation
PatchMapping
This is an alias for Patch.
Post
Post Route Annotation
PostMapping
This is an alias for Post.
Put
Put Route Annotation
PutMapping
This is an alias for Put.
Repository
This is an alias for Injectable.
Service
This is an alias for Injectable.

Derive Macros§

RupringDto
RupringDto derive macro