R3 Good practices applied
Scalability and performance
Defining compressing for data exchange
// Defining default Compress level for data exchange
.wrap(middleware::Compress::new(ContentEncoding::Gzip))
Static Configuration and default config
- First we look for a distributed configuration server (etcd)
- If it fails, we take the configuration values located in an .env file
- And if this also fails, we have the default configuration (initialized variables)
let mut port: String = String::from("3030");
let mut host: String = String::from("127.0.0.1");
let client_etcd = Client::connect(["localhost:2379"], None).await;
if client_etcd.is_ok(){
let mut client_unwrap = client_etcd.unwrap();
let resp_etc_host = client_unwrap.get("HOST", None).await;
let resp_etc_port = client_unwrap.get("PORT", None).await;
host = String::from(resp_etc_host.unwrap().kvs().first().unwrap().value_str().unwrap().to_string().as_str());
port = String::from(resp_etc_port.unwrap().kvs().first().unwrap().value_str().unwrap().to_string().as_str());
log::info!("Host from etcd: {:?}", host);
log::info!("Port from etcd: {:?}", port);
}else{
log::info!("No client etc, we will use .env");
}
dotenv().ok();
port = env::var("PORT").expect("PORT must be set");
host = env::var("HOST").expect("HOST must be set");
Security
Define a subset of accepted verbs (the ones we use, the rest are not accepted)
.wrap(middleware::DefaultHeaders::new().header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE"))
Preventing XSS Attempt (Not useful if request is not from browser)
.wrap(middleware::DefaultHeaders::new().header("X-XSS-Protection", "1; mode=block"))
Preventing embedding
.wrap(middleware::DefaultHeaders::new().header("X-Frame-Options","Deny"))
Only allow our same origin scripts
.wrap(middleware::DefaultHeaders::new().header("Content-Security-Policy","script-src 'self'"))
Preventing CSRF attacks
.wrap(middleware::DefaultHeaders::new().header("Access-Control-Allow-Headers", "X-Requested-Width"))
Functionality
Only JSON exchange
.wrap(middleware::DefaultHeaders::new().header("Content-Type", "application/json"))
Use of (customs) logs (and inject them in api) for every event in backend
// Define format of our logs
env_logger::Builder::from_env(Env::default().default_filter_or("info").write_style_or("auto", "always"))
.format(|buf, record| {
writeln!(
buf,
"{} {}: {}",
record.level(),
//Format like you want to: <-----------------
Local::now().format("%Y-%m-%d %H:%M:%S%.3f"),
record.args()
)
})
.init();
log::info!("Welcome to cloudbanking API {}", VERSION_ENV);
log::info!("Server is listening in {}", binding_uri);
Same in kotlin
import org.jboss.logging.Logger
companion object {
private val LOG = Logger.getLogger(FundResource::class.java)
}
LOG.info("POST -> Fund was created")