Hi,
Is it possible to prepare a multi tenant application with Actix, ntex or axum?
For example, I want to get the database settings after checking the request header and getting the site name. (X-Application-Site) We can achieve this using the code request.headers.get('X-Application-Site-Name') with Python. If I can create a structure this way, I can get the settings from the site's folder and use separate database for each site.
But I couldn't find how to go about it. I am planning to read settings from json file by checking database and all settings in request header.
Example json file:
{
"db_name": "_452bb8a54116ac67",
"db_password": "4eFlqrOeu6abyZTR",
"db_type": "postgresql",
"limits": {
"emails": 1500,
"expiry": "2030-01-01",
"space": 50.0,
"users": 50
},
}
I'll be happy if you can help me.
I suppose you could do something like this
use axum::{
async_trait,
extract::{Extension, FromRequest, RequestParts},
http::StatusCode,
response::{IntoResponse, Response},
routing::get,
Router,
};
#[tokio::main]
async fn main() {
let databases = Databases {};
let app = Router::new()
.route("/", get(handler))
.layer(Extension(databases));
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
#[derive(Clone)]
struct Databases {}
impl Databases {
fn get_database_for_site(&self, application_site_name: &str) -> Option<DatabaseForSite> {
todo!()
}
}
#[async_trait]
impl<B> FromRequest<B> for DatabaseForSite
where
B: Send,
{
type Rejection = Response;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
// look up the header
let application_site_name = req
.headers()
.ok_or_else(|| StatusCode::INTERNAL_SERVER_ERROR.into_response())?
.get("x-application-site-name")
.and_then(|value| value.to_str().ok())
.ok_or_else(|| {
(
StatusCode::BAD_REQUEST,
"x-application-site-name header missing",
)
.into_response()
})?;
// get the database for the site name
let databases = req
.extensions()
.ok_or_else(|| StatusCode::INTERNAL_SERVER_ERROR.into_response())?
.get::<Databases>()
.ok_or_else(|| StatusCode::INTERNAL_SERVER_ERROR.into_response())?;
let database = databases
.get_database_for_site(application_site_name)
.ok_or_else(|| StatusCode::BAD_REQUEST.into_response())?;
Ok(database)
}
}
#[derive(Clone)]
struct DatabaseForSite {}
async fn handler(db: DatabaseForSite) -> impl IntoResponse {
// use the database
}
system
Closed
June 9, 2022, 11:06am
3
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.