'러스트 박살내기(?)' 시리즈Rust-Lang의 웹 프레임워크 🚀Rocket

배진오

@baealex

소비적인 일보단 생산적인 일을 좋아합니다.

러스트로 웹 개발에 발을 담그려는데 러스트에 어떤 웹 프레임워크가 있으며 어떤 프레임워크를 선택할지 고민하는 글이다. 필자는 프레임워크 선택시 가장 중요하게 생각하는 부분은 프레임워크의 튜토리얼이다. 튜토리얼이 재밌는 글은 확실히 프레임워크가 어떤 부분에 중점을 맞췄는지 이해하기 쉽더라.


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의 경우 웹 개발의 미래지향적 기술들만 사용되어 굉장히 매력적이라 생각된다. 차후에 꼭 다뤄봐야겠다. 우선 익숙한 웹 개발 환경으로 보이는 ACTIXRocket 중에 선택하려 한다.

위 자료에서 로켓과 니켈의 비교가 이뤄지고 있는데 커뮤니티에선 Rocket 보다는 ACTIX를 추천한다. RocketREST 아키텍처 혹은 초보자에게 적합하며 ACTIXHTTP 응용 프로그램에 가까운 프로젝트 혹은 숙련자에게 적합하다는 언급이 많으므로

로켓으로 탑승하자!


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 %}

장고 문법이랑 똑같다. 편ㅡ안. 현재 indexname이라는 값을 전달하고 있는데 이 값 전달하는 것도 장고와 똑같다. 딕셔너리(해쉬맵) 형태로 전달해주면 된다.

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();
}


멋지게 결과가 출력되는 것을 볼 수 있다.

'러스트 박살내기(?)' 시리즈

러스트... 부셔버리겠어! 🔥🔥🔥 는... 내가 박살나는 중... 😥😫
😥 작성된 댓글이 없습니다!
댓글을 작성하기 위해 로그인이 필요합니다.