Rust Actix-Web - II

Veli Uysal
Turkiye Rust Community
3 min readAug 8, 2023

--

Daha önceki yazımda Actix-Web frameworkünden bahsetmiştim. Bu yazımda ise bir web uygulamasında kullanılan kısımları ele alacağım. Haydi başlayalım.

Bir Rest API geliştirirken Actix frameworküyle kullanabildiğimiz metot ve kavramlara gelin bir göz atalım.

Route kavramı

Diğer dillerde de olan bu kavram bizim URI olarak hangi adrese ulaşabileceğimizi belirleyen yapıdır. Route ile birlikte bizim daha önce tanımladığımız bir scope yok ise direkt sunucumuzun URI’sinin sonuna Route içerisine tanımaldığımız URL dikkate alınır.

#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Note: web::Data created _outside_ HttpServer::new closure
let counter = web::Data::new(AppStateWithCounter {
counter: Mutex::new(0),
}); HttpServer::new(move || {
// move counter into the closure
App::new()
.app_data(counter.clone()) // <- register the created data
.route("/", web::get().to(index))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}

Yukarıdaki örnekte 127.0.0.1:8080 üzerinde çalışan kodlarımıza Route olarak “/” tanımlanan URI için bizim index isimli metodumuz çağrılacaktır.

Uygulama Kapsamı Kavramı( web::scope() )

web::scope() metodu ile bizim belirli bir iş modeline sahip URI’leri gruplandırmak için kullanabileceğimiz ayarları yapmamızı sağlar. Bu yöntemle birlikte tüm kaynak kalıplarının başına eklenen bir kaynak önekiyle temsil edilir. Bunun kullanım örneği aşağıda verilmiştir.

#[actix_web::main]
async fn main() {
let scope = web::scope("/users").service(show_users);
App::new().service(scope);
}

Yukarıdaki örnekte “/users” URI’sine karşılık gelen bir hizmet metodu yazılarak bizim browser üzerinden domainimizde bulunan “/users” URI’sine istek attığımızda bu metot tetiklenerek bize bir değer döndürmesi gerçekleştirilir. Bu kavram ile biz api’lerimizde aynı tip işlemleri yapan endpointleri bir araya getirmiş ve bizim URI’lerimizde ise aynı üst URI’den erişilebilir hale getirmiş oluyoruz.

Configure kullanımı

Bizim endpointlerimizi belirli bir konfigürasyonla işlemlere dahil etmek istediğimizde kullandığımız yapıdır. Bu konfigürasyonu istersek aynı dosya içerisinde oluşturduğumuz farklı bir metot ile kullanabilir ya da ayrı bir dosya içerisinden çağırarak kullanabiliriz. Configure kullanmamızın nedenleri;

  • Basitlik ve yeniden kullanılabilirlik için hem Uygulama hem de web::Scope yapılandırma yöntemini sağlaması.
  • Konfigürasyonun parçalarını farklı bir modüle veya farklı library’e taşımayabilmemize imkan sağlaması.
use actix_web::{web, App, HttpResponse, HttpServer};

// this function could be located in a different module
fn scoped_config(cfg: &mut web::ServiceConfig) {
cfg.service(
web::resource("/test")
.route(web::get().to(|| async { HttpResponse::Ok().body("test") }))
.route(web::head().to(HttpResponse::MethodNotAllowed)),
);
}

// this function could be located in a different module
fn config(cfg: &mut web::ServiceConfig) {
cfg.service(
web::resource("/app")
.route(web::get().to(|| async { HttpResponse::Ok().body("app") }))
.route(web::head().to(HttpResponse::MethodNotAllowed)),
);
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.configure(config)
.service(web::scope("/api").configure(scoped_config))
.route(
"/",
web::get().to(|| async { HttpResponse::Ok().body("/") }),
)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}

Yukarıdaki örnekte bizim endpointlerimizi configure kullanarak farklı bir metot içerisinde nasıl kullanabileceğimizi gördük. Bu yapının çıktısı ise aşağıdaki gibi olacaktır.

/         -> "/"
/app -> "app"
/api/test -> "test"

TLS/HTTPS desteği eklenmesi

Geliştirdiğimiz projede bizim Actix ile geliştirdiğimiz kodlara güvenli bir erişim olmasını istediğimiz durumda ilave olarak rustls veya openssl kütüphanesini projemize eklememiz gerekmektedir. Ekleme işlemi olarak aşağıdaki gibi Cargo.toml dosyasına ekleme yapabiliriz.

[dependencies]
actix-web = { version = "4", features = ["openssl"] }
openssl = { version = "0.10" }

Yuakrıda dikkat ederseniz Actix kütüphanesine features olarak “openssl” kütüphanesi eklenmektedir.

Bunun nedenini size bırakıyorum :)

Daha sonra bu kütüphaneyi kullanmak için ilk başta bizim bir ssl key oluşturmamız gerekmektedir. Aşağıdaki kodları çalıştırarak oluşturabilirsiniz.

$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
-days 365 -sha256 -subj "/C=CN/ST=Fujian/L=Xiamen/O=TVlinux/OU=Org/CN=muro.lxd"

Daha sonra oluşturulan key değerini nopass.pem dosyasına kopyalıyalım.

$ openssl rsa -in key.pem -out nopass.pem

Bu işlemlerden sonra Actix ile geliştirdiğimiz projemizde gerekli kodları eklememiz gerekmektedir. En basit ekleme işlemi için aşağıdaki kodları kullanabilirsiniz.

use actix_web::{get, App, HttpRequest, HttpServer, Responder};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};

#[get("/")]
async fn index(_req: HttpRequest) -> impl Responder {
"Welcome!"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
// load TLS keys
// to create a self-signed temporary cert for testing:
// `openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'`
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder
.set_private_key_file("key.pem", SslFiletype::PEM)
.unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();

HttpServer::new(|| App::new().service(index))
.bind_openssl("127.0.0.1:8080", builder)?
.run()
.await
}

Daha sonraki yazılarımda detaylarına ineceğim.

Sosyal medya hesaplarım: Twitter | Linkedin | Github | Youtube

--

--