러스트로 웹 개발에 발을 담그려는데 러스트에 어떤 웹 프레임워크가 있으며 어떤 프레임워크를 선택할지 고민하는 글이다. 필자는 프레임워크 선택시 가장 중요하게 생각하는 부분은 프레임워크의 튜토리얼이다. 튜토리얼이 재밌는 글은 확실히 프레임워크가 어떤 부분에 중점을 맞췄는지 이해하기 쉽더라.
Web Framework
러스트의 웹 프레임워크를 검색하여 다음의 프레임워크들을 발견할 수 있었다.
- ACTIX : 가장 빠름. 숙련자에게 추천되는 프레임워크. 서버 렌더링 지원. 깃허브 스타 7800개. 마지막 업데이트 2020년 04월.
- Rocket : 입문자에게 추천되는 프레임워크. JSON응답 기본 제공. 서버 렌더링 지원. 깃허브 스타 9400개. 마지막 업데이트 2020년 03월.
- Nickel : 가벼움. 미들웨어로 확장할 수 있음. 서버 렌더링 지원. 깃허브 스타 2700개. 마지막 업데이트 2019년 10월.
- Yew : React에 영감얻음. WASM에 적합함. 컴포넌트 재사용 가능. 깃허브 스타 11200개. 마지막 업데이트 2020년 04월.
필자가 러스트에 관심을 가지게 된 이유는 Nickel
때문이었다. 웹 프레임워크 속도 비교에서 Nickel
이 1등 자리에 있었는데 "이건 뭔데 이렇게 빠를까?"라는 생각으로 흥미를 가졌었다. 하지만 마지막 업데이트가 작년이라... 좀 신경쓰인다. Yew
의 경우 웹 개발의 미래지향적 기술들만 사용되어 굉장히 매력적이라 생각된다. 차후에 꼭 다뤄봐야겠다. 우선 익숙한 웹 개발 환경으로 보이는 ACTIX
와 Rocket
중에 선택하려 한다.
위 자료에서 로켓과 니켈의 비교가 이뤄지고 있는데 커뮤니티에선 Rocket
보다는 ACTIX
를 추천한다. Rocket
은 REST
아키텍처 혹은 초보자에게 적합하며 ACTIX
는 HTTP
응용 프로그램에 가까운 프로젝트 혹은 숙련자에게 적합하다는 언급이 많으므로
로켓으로 탑승하자!
Rocket
처음 컴파일을 시도 했을 때 버전과 관련된 문제가 발생했다. 이에 대해 문서에 언급이 되어있는데
Rocket은 Rust의 구문 확장과 기타 고급 불안정 기능을 사용하므로 Nightly 버전을 사용해야합니다.
rustup default nightly
위 명령어를 이용해 러스트를 nightly
버전으로 바꿔주자.
Terminal
cargo new hello-rocket --bin
cd hello-rocket
Cargo.toml
[dependencies]
rocket = "0.4.4"
main.rs
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket;
#[get("/")]
fn index() -> &'static str {
"Hello, world!"
}
fn main() {
rocket::ignite().mount("/", routes![index]).launch();
}
main.rs
를 위와 같은 내용으로 바꿔준뒤 cargo run
를 입력하면
🚀 Rocket has launched from http://localhost:8000
위 문장을 볼 수 있다. 표시된 경로에 접속하면 Hello World
라는 문장이 보여진다.
Template
로켓에서 탬플릿을 사용하기 위해선 Cargo.toml
에 아래 내용을 추가해 주어야한다. 로켓에선 기본 템플릿으로 tera
라는 템플릿 엔진을 사용하고 있는데 Django
의 템플릿 문법과 아주 유사하다.
Cargo.toml
[dependencies.rocket_contrib]
version = "0.4.4"
features = ["tera_templates"]
main.rs
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket;
extern crate rocket_contrib;
use rocket_contrib::templates::Template;
#[get("/")]
fn index() -> Template {
let mut context = ();
Template::render("index", &context)
}
fn main() {
rocket::ignite()
.mount("/", routes![index])
.attach(Template::fairing())
.launch();
}
이제 templates
라는 디렉터리를 생성하여 그곳에 템플릿 파일일 삽입하자.
- src
- main.rs
- templates
- base.html.tera
- index.html.tera
- Cargo.toml
base.html.tera
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
{% block body %}
{% endblock body %}
</body>
</html>
index.html.tera
{% extends "base" %}
{% block body %}
<h1>Hello, {{ name }}.</h1>
{% endblock body %}
장고 문법이랑 똑같다. 편ㅡ안. 현재 index
에 name
이라는 값을 전달하고 있는데 이 값 전달하는 것도 장고와 똑같다. 딕셔너리(해쉬맵) 형태로 전달해주면 된다.
main.rs
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket;
extern crate rocket_contrib;
use rocket_contrib::templates::Template;
use std::collections::HashMap;
#[get("/")]
fn index() -> Template {
let mut context = HashMap::new();
context.insert(
"name".to_string(),
"Jino Bae".to_string(),
);
Template::render("index", &context)
}
fn main() {
rocket::ignite()
.mount("/", routes![index])
.attach(Template::fairing())
.launch();
}
멋지게 결과가 출력되는 것을 볼 수 있다.
Ghost