nano-rs is a lightweight, non-invasive, convention-over-configuration Rust Web service component, aimed at providing a fast and efficient development experience. By reducing the burden of configuration, it allows you to focus more on implementing business logic.
- Lightweight: Ensures fast startup and low resource consumption through a streamlined design.
- Non-invasive: The framework's design allows for seamless integration into existing Rust projects without fear of interfering with business logic.
- Convention Over Configuration: The framework adopts an "intelligent defaults" approach, providing pre-set configurations for common scenarios. This means you can get started with little to no configuration, yet it still offers ample configuration options to suit specific needs ensuring ultimate flexibility and extensibility.
- Business Focused: Our goal is to simplify the development process of Web services. By reducing the tedious and miscellaneous configuration tasks, you can concentrate more on implementing the business logic, thus improving the efficiency and quality of project development.
Table of Contents
MSRV >= 1.66
cargo add nano-rs
- Add build dependencies
[build-dependencies]
nano-rs = "0.1.3"
nano-rs-build = "0.1.2"
- Add gen component build.rs
use std::error::Error;
use nano_rs_build::core::NanoBuilder;
use nano_rs::axum::generator::gen_route::AxumGenRoute;
fn main() -> Result<(), Box<dyn Error>> {
NanoBuilder::new(None).gen_api_route(AxumGenRoute::new());
Ok(())
}
- Add the configuration file to your desired directory (in the example, it is placed in etc/config.yaml)
port: 8888
name: example
host: 127.0.0.1
- Write your API code anywhere in project with marco (for example, under api/pet), for macros, please refer to example
#[get(path = "/store/name", layers = ["crate::layers::auth::auth_token1"])]
pub async fn get_store_name() -> Result<RestResp<String>, ServerError> {
biz_ok("Doggy Store".to_string())
}
- Run build once (only needed for the project's first compilation)
cargo build
- Then you will get file named
routes.rs
in yoursrc/
. - Do not edit
routes.rs
as it will be overwritten every time you build. - Edit
main.rs
. (refer to the project structure in the example)
use axum::Router;
use nano_rs_core::config::rest::RestConfig;
use axum_client_ip::ClientIpSource;
use nano_rs_extra::axum::start::AppStarter;
#[tokio::main]
async fn main() {
let rest_config = nano_rs_core::config::init_config_with_cli::<RestConfig>();
let _guards = nano_rs_core::tracing::init_tracing(&rest_config);
let service_context = ServiceContext {
rest_config: rest_config.clone(),
};
let app = Router::new();
AppStarter::new(app, rest_config)
.add_log_layer()
///if use nginx proxy,you can use ClientIpSource::XRealIp
.add_secure_client_ip_source_layer(ClientIpSource::XRealIp)
.run()
.await;
}
#[derive(Clone)]
pub struct ServiceContext {
pub rest_config: RestConfig,
}
- Run your web application
cargo run -- --config etc/config.yaml
- After this, you only need to focus on writing your business logic code; nano-rs will automatically generate routes and register them with axum, allowing you to concentrate solely on implementing business logic.
- Add build dependencies
[build-dependencies]
nano-rs = { version = "0.1.3", features = ["utoipa_axum"] }
nano-rs-build = "0.1.2"
utoipa = { version = "5.1.1", features = ["axum_extras"] }
- Add gen component to build.rs
use std::error::Error;
use nano_rs_build::core::NanoBuilder;
use nano_rs::axum::generator::gen_route::AxumGenRoute;
fn main() -> Result<(), Box<dyn Error>> {
NanoBuilder::new(None)
.gen_api_route(AxumGenRoute::new())
.gen_api_doc(AxumGenDoc::new()
.set_info(InfoBuilder::new()
.title("Pet")
.description(Some("Pet Api Server"))
.terms_of_service(Some("https://example.com"))
.contact(Some(ContactBuilder::new()
.name(Some("Pet"))
.email(Some("pet@gmail.com"))
.build()))
.version("v1")
.build())
.add_server(ServerBuilder::new()
.url("")
.description(Some("dev"))
.build())
.add_server(ServerBuilder::new()
.url("https://example.com")
.description(Some("prod"))
.build())
.build());
Ok(())
}
/// Get pet by id
#[utoipa::path(
get,
path = "/store/pet",
tag = "Store",
params(QueryPet),
responses(
(status = 200, body = Pet)
)
)]
#[get()]
pub async fn get_query_pet_name(Query(query): Query<QueryPet>) -> Result<RestResp<Pet>, ServerError> {
biz_ok(Pet {
id: query.id,
name: "Doggy".to_string(),
tag: None,
inline: None,
meta: Meta { name: "Doggy".to_string(), age: 1 },
})
}
- If enable utoipa_axum features,you don't need write path or group code(unless you need a layer),just write utoipa code,then you can get openapi document and axum route.
- Run build once (only needed for the project's first compilation)
cargo build
-
Then you will get file named
doc.rs
in yoursrc/
. -
Do not edit
doc.rs
as it will be overwritten every time you build. -
Now you can use
doc.rs
to generate openapi document, see example -
Run your web application
cargo run -- --config etc/config.yaml
- Add build dependencies
[build-dependencies]
nano-rs = "0.1.3"
nano-rs-build = "0.1.2"
- Add build.rs
fn main() -> Result<(), Box<dyn Error>> {
NanoBuilder::new(None)
.gen_api_route(AxumGenRoute::new())
.gen_api_info(AxumGenApiInfo::new());
Ok(())
}
- This will gen
api_info.rs
in yoursrc/
for collect your all api info,and you can useget_api_info()
to get all api info.
- Cause seaorm does not support postgresql doc generation, so we provide a way to generate it.
- Add build dependencies
[build-dependencies]
nano-rs-extra = { version = "0.1.4" }
tokio = { version = "1.34.0", features = ["full"] }
- Add build.rs
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let database_url = "postgres://test:test@localhost/test".to_string();
let database = "test".to_string();
let schema = None;
GenComments::new(None, database_url, database, schema).gen_comments().await?;
Ok(())
}
- Run build once (only needed for the project's first compilation)
- It will inject doc into your entity field from your postgresql database when you already make doc in field.
- Before build
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::fruit::Entity")]
Fruit,
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl ActiveModelBehavior for ActiveModel {}
- After build
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
/// cake id
pub id: i32,
/// cake name
pub name: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::fruit::Entity")]
Fruit,
}
impl Related<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl ActiveModelBehavior for ActiveModel {}
- Auto-generate Axum framework routes
- Default configuration for Tracing framework
- Preset common web service configuration (managed via yaml)
- Auto-generate OpenApi (gen utoipa struct)
For a full list of proposed features (and known issues), please see the open issues.
Distributed under the MIT License. For more information, see LICENSE.txt
.