アジェンダの紹介

kenkoooo氏:では僕、kenkooooが「actix-webで快適Webアプリ生活」というタイトルで発表します。よろしくお願いします。

(スライドを示して)今日発表したいことは、actix-webというRustのWebフレームワークが、どれだけ使いやすいかということです。それから、これは立ち入った話なのですが、actix-webのミドルウェアという機能があって、それも今estie(株式会社estie)でけっこう使っているので、その話をできればと思います。

Rustで作られたWebフレームワーク「actix-web」

まずは、「actix-webで爆速Webアプリ開発」の話をします。actix-webとは何か。Webフレームワークは、プログラミング言語ごとにいろいろあると思っています。例えば、PythonのDjangoやFlask、JavaだとSpring Frameworkが有名だと思います。Rustにもいろいろあって、actix-webやRocket、あとはtideなど、いろいろなものがあります。

actix-webはRustの中ではわりと広く使われています。たぶん1番目か2番目ぐらいに広く使われているWebフレームワークです。機能もすごく多くて、Webアプリでこういうことをやりたいというのが、だいたい全部入っている感じの、かなり広くカバーしているWebフレームワークです。

あとはドキュメントがすごく詳しいです。Rustは、古参のライブラリのドキュメントがわりと詳しいものが多いのですが、その中でも単純にライブラリのドキュメントだけではなくて、実際のユースケースに合わせたドキュメントがけっこうあります。

また、exampleがすごくいっぱいあります。to doリストのWebアプリを作るためのチュートリアルみたいなものがよくあると思いますが、そういう感じで他にも、SQLと組み合わせたらどうとか、この他のサードパーティのサービスと組み合わせたらどうみたいな感じで、exampleがすごく充実しています。「こういうのをやりたい」というのがすぐできるのがactix-webのすごく良いところかなと個人的には思っています。

actix-webを使うとWebアプリが書ける

(スライドを示して)今日はどういう人たちが(イベントに)来るのかがわからなかったので、かなり初歩的な話になります。「知ってるよ」という人もたくさんいると思うのですが、一応少し話します。

Webフレームワークが何をするものなのか。そもそもWebアプリがなにかというと、みなさんがブラウザーを開いた時に、なにかを表示するアプリですね。どういうふうになっているかというと、ブラウザーを開いた時にサーバーにリクエストがいきます。

これで「こういうのを見せてください」とリクエストをします。例えば「index.htmlっていうのをください」とGETリクエストをします。また、Twitterをやる時は、POSTというのですが、「新しいツイートを受け取ってください」というのを、こちら(ブラウザー)から送ります。

先ほどのGETだと「ください」と言っただけで、くれるのは向こう(サーバー)なのですが、POSTだったら、相手に「こういうのあげます」みたいな感じです。

こういうふうにブラウザーとやり取りするものがあって、これをサーバーといいます。

ここ(サーバー)の部分を、actix-webが代わりにやってくれます。(スライドを示して)こういう感じですね。ブラウザーが「こういうのお願いします」とリクエストをサーバーに送って、そのサーバーで動いているactix-webで作られたRustのWebアプリが、そのリクエストを受け取って、それに応じてレスポンスを返します。そういう感じでサーバーのアプリケーションは動いていて、そういうものを開発する時にすごく便利なのが、actix-webというフレームワークです。

(スライドを示して)actix-webを使うと、メチャクチャ簡単にこういうWebアプリが書けます。リクエストを受け取ってレスポンスを返すなど、いろいろなことをやりたいのですが、すごく簡単に書けます。

ちなみに簡単じゃなくてよければ、公式のドキュメントがあります。これはちょっとURLが間違っているのですが、この名前でググればたぶん出てきます。「The Rust Programming Language」という、そのままの名前のサイトがあります。

公式のチュートリアルは、この値をここに代入しますみたいな、すごく基本的な話から始まるのですが、最後の章では、フレームワークなしでWebサーバーを作るというのをやっています。

(スライドを示して)ちなみにThe Rust Programming Languageというページにいくと、こういう感じで、イチからRustでWebサーバーを作るというのがあるので、もしよかったらちょっとチャレンジしてみてください。

GETリクエスト受け取り→レスポンスは4行で実現できる

Webフレームワークは先ほども言ったとおり、GETリクエストの「index.htmlをください」というのを受け取って、レスポンスを返すというものです。

(スライドを示して)これが、これだけでできます。これで本当に全部です。メイン関数も含めて、これだけをメインファイルにコピーしてもらえればもう、このまま動きます。

この下の段の部分は、サーバーを立ち上げるために必要なメイン関数の部分なのですが、重要なのは「index.htmlをください」というリクエストを受け取って、そのレスポンスを返す部分です。その部分に関してはもうこれだけ、この4行だけで実現できます。

ここ(オレンジの枠内)をちょっと見てみると、すごくわかりやすくて、このパスを指定されたGETリクエストを受け取ります。これは関数で、Rustだと関数はこういう感じで書きます。ここはちょっと特殊な書き方になっていますが、こういう感じで書いて、ここにレスポンスで返したい内容を入れます。

なので、この関数の中身でレスポンスを生成してやればいい感じです。これだけで本当にactix-webでWebサーバー、Webアプリを作れます。

Twitterのようなものを作りたい場合

今はGETリクエストでやったのですが、例えば、Twitterのようなものを作りたいとなったら、今度はPOSTリクエストを受け取るようにして、ここのパスに来たリクエストを受け取ります。こういうふうに書くと、ブラウザーからなにかをポストされるものも作れます。

今は引数に何も取っていない関数ですが、例えば引数に、ブラウザーから送られてくる、リクエストBodyを入れれば、actix-web側でいろいろやって、最後にRust側で処理しやすくなったかたちのものが、そのまま受け取れます。なので、あとはこれを使って、この関数の中でいろいろやってあげればいいので、すごく簡単に書けます。

(スライドを示して)これを関数の引数として渡すと、actix-webがBodyとして受け取ります。これは、ちょっとフォーマット変えただけで、先ほどと同じ関数です。

ここでは、先ほどリクエストで来たものを受け取れるのですが、実際にやりたいことは、ブラウザーと関数の2つではなく、例えばブラウザーで受け取ったものをデータベースに保存するなど、もっと他の登場人物がいるはずで、そういうものも扱いたいんですね。

でもこれは関数なので、そういうのをどういうふうに扱ったらいいかはけっこう難しいところです。

これもactix-webだったらこんな感じで、引数に必要なものを渡してやるだけで、あとはフレームワーク側でうまくやって、引数に必要なものを届けてくれます。

なので、ここはリクエストからきたもので、ここは自分のサーバーの中にあるデータベースや他のものでもいいです。クライアントを渡してくれたりという感じで、これはRustの書き方というか、actixの書き方です。

Dataとしてこいつを渡せば、リクエストがきた時、そのリクエストに入っていたBodyの中身だけではなく、必要なものも全部持ってきてくれるので、関数の引数に必要なものを、ババババッと入れるだけで、あとはうまいこと思ったとおりに動いてくれる感じです。

例えばツイートするクライアントだけではなく、キャッシュも使いたいとかいろいろあると思うのですが、それも関数の引数としてどんどん足していくだけで、使えるようになります。

シンプルな関数を定義するだけでWebアプリが作れる

(スライドを示して)本当にこれだけでWebアプリが動くようになるので、actixですごく簡単にWebアプリが作れます。1つ1つの機能を関数として書くだけで動きます。

例えばリクエストの中身が必要だったり、他のサービスとつなぎたくてクライアントが必要だったり、データベースが必要だったり、いろいろありますが、それも全部引数に渡してやると、メイン関数の中でちょっと設定する必要はあるのですが、基本的には引数に足してやれば、あとはフレームワークからどんどん必要なものを渡してくれます。

という感じで、すごく書きやすいですね。Webアプリを作る時は、本当にこういうシンプルな関数を定義するだけなので、内容のロジックに集中できます。

というのがactix-webで、Webアプリが超簡単に作れるようになりました。

actix-webミドルウェアとは何か

actix-webミドルウェアの話をします。

先ほど話したとおり、actix-webさえあれば、とりあえずWebアプリは超簡単に作れるのがわかりました。(スライドを示して)ブラウザーから来たリクエストを、フレームワーク側は生で受け取っているのですが、実際はこういう感じになっています。

そのリクエストを受け取って、フレームワークがいい感じにやって、こっちのRustの関数で使える引数のかたちにして渡してくれます。この関数が返した返り値をフレームワーク側でまたいい感じにやって、HTTPのレスポンスにしてブラウザーに返してくれる感じで、このフレームワークがいい感じにやってくれます。

これで十分便利なのですが、リクエストを受け取って、そのリクエストからユーザー情報を拾ってきて、その引数に付け加えてほしいみたいな、もっと良くするアイデアがあったとします。Bodyの中に含まれていなくても、こちら側ですでに持っている情報で、欲しい情報があって、そういうのを事前にフレームワーク側でいい感じにやってほしい。リクエストがきたら、データベースからユーザー情報を引っ張ってきて、関数に一緒に渡してほしいみたいなことをやりたくなります。

それをやるのが、actixミドルウェアです。今はミドルウェアと抽象的に話していますが、実際には、いろいろなミドルウェアみたいなのを自分で定義してやります。そして、最後にリクエストが、最初に定義した関数に渡る前にいろいろ前処理をしてくれるものになります。

もう少し細かく言うと、その後処理もやってくれたりとか、いろいろあるのですが、使いたい機能は、HTTPリクエストの前処理をしたいということです。

actix-webミドルウェアは簡単に書ける

(スライドを示して)ミドルウェアも実はすごく簡単に書くことができます。先ほどの関数ほど簡単ではないですが、こういう感じで動いているのが、かなり簡単に書けます。なにをやっているかというと、このcallという1つの関数を自分で実装すればいいです。

この、Serviceリクエストがブラウザーから来て、フレームワークでいろいろ処理されて、ミドルウェアに届きます。

このServiceリクエストに対して、いろいろ処理します。例えば、Serviceリクエストの中に入っているユーザーIDを見つけて、自分たちがもうすでに持っているデータベースからユーザー情報を引っ張ってきて、最後に次のサービスに渡すという感じですね。

ミドルウェアは順番に並んでいるので、1番で処理したあと、そのServiceリクエストで2番に渡って、3番に渡ってという感じで、最後に自分たちが定義したここの関数に落ちてくる感じです。1個のミドルウェアの中では、リクエストを処理して、そのあと次のサービスに渡すみたいな感じの処理になります。

先ほどの例だとどういうふうにやるかというと、例えばこのcallという関数を1つ定義すればいいだけなので、こんな感じでリクエストがきたら、その中からtokenをパースして、取り出します。

そのtokenを使って今度はユーザー情報をゲットして、最後にそのユーザー情報を、リクエストに詰めます。受け取ったリクエストにユーザー情報をギュッと入れて、それをまた次のサービスに渡す感じでミドルウェアを使っています。

先ほどのリクエストに入っている中身と、リクエストを処理するのに必要なやつをフレームワークから関数に渡してもらっていたのですが、もう1個、このデータとは別のリクエストデータみたいなものがあります。そういうふうに関数で定義すれば、あとはフレームワークでいい感じにリクエストデータをサービスリクエストから生成して、関数に渡してくれます。

簡単にできる分、かゆいところに手が届かないみたいなことが、簡単に使えるものにはよくあるのですが、実はactixはカスタマイズもすごく簡単です。ミドルウェアをどんどん並べていくだけで、いろいろなカスタマイズを組み合わせて使えます。

開発者は関数の中身の処理を実装することだけに集中できる

僕の発表の内容は以上です。actix-webを使えば簡単にWebアプリが作れるというのが伝わればうれしいです。

(スライドを示して)こういう感じで作りたい、サービス側に持たせたい機能を、それぞれ機能ごとに1つの関数として定義して、必要なものは全部引数の中に入れれば、あとはここの引数側の処理は、全部サーバーがうまい具合にリクエストの中身を取り出したり、あるいは、サーバーにもともと入っているツールを持ってきてくれたり、リクエストからミドルウェアが生成してくれたデータを引数に渡してくれるので、開発者はここの関数の中身の処理を実装することだけに集中できます。

Rustを導入してよかったこと

これで「actix-webで爆速Webアプリ生活」は以上です。オマケコンテンツじゃないですが、僕は入社前の2021年12月ぐらいから、アルバイトで働いているのですが、Rust導入から5ヶ月ぐらい経ったので、技術的な話ではないのですが、どんな感じかをちょっと話します。

(スライドを示して)5ヶ月経って、プロダクトは1つリリースできました。プレスリリースを出してはいないのですが、お客さまにちょっと使ってもらったりもしています。現状はすでにプロダクトをリリースして運用している状態で、まだまだ作りたい機能がいっぱいあるので、ぜひみなさんに入社してもらいたいと思っています。

導入してよかったこと。これはもしかしたら僕が勝手に思っているだけで、他のチームメイトがどう思っているかはわからないのですが、生産性がすごく高いと思っています。

他の言語だと、デファクトになっているパッケージマネージャーがあったりするのですが、Rustは言語自体にすごくいろいろな機能が入っている上に、公式のパッケージマネージャーがあって、いろいろなサードパーティのパッケージがすでにいっぱいあるので、ライブラリの追加がすごくしやすいです。

それから、僕はエディタの補完機能をメチャクチャ使うのですが、rust-analyzerというすごく強い補完をしてくれるツールがあって、各エディタの拡張機能として使えるのがとにかくいいです。

Rustコンパイルが一生通らないみたいなのが、よくあると思うのですが、そういうのもコンパイルするまでもなくrust-analyzerが全部見つけて、直し方をだいたい教えてくれるので、生産性がすごく向上しています。

さらに、Rust流の設計を強制されるのが、けっこう重要な点だと思っています。Rustはリソース管理みたいなのが、すごくしっかりしています。よくあるのはメモリ管理をちゃんとやれみたいなやつですが、その参照を持ち回しません。

JavaやPythonでよくある、参照を持ち回すみたいなことが、Rustだとかなりやりづらくなっていて、良い設計を強制されるのがすごくいいなぁと思っています。

Rustを導入して大変だったこと

逆に大変なのは、公式のSDKがいろいろなサービスで提供されていないことです。JavaやPython、あと時々RubyもSDKがあったりすると思うのですが、そういうのが基本的にありません。

今僕たちが作っているサービスは、すでにDatadogやSendGridや、Auth0などのサービスと、インテグレーションしているのですが、そういうところで公式のSDKがないので、自分たちで実装しないといけません。

あとは他のメンバーにどういうふうに、Rustを学んでもらうかというのもすごくあって、これはちょっとまだ試行錯誤中です。ですが、スケルトンプロジェクトでもいいので、とりあえず動くプロジェクトがあれば、その上でなにか書いて動かしてみて、コンパイルが通らなかったら直してという感じで、試行錯誤ができます。

1つのプロダクトがもうあるというのは、すごく勉強しやすい環境なのかなと思っています。あとはコードレビューをきちんとやること。これはたぶんRustに限らないと思います。

それから、Rustの場合はコンパイラがすごく親切なので、それが教育にも一役買ってくれているところはあると思います。

Rustで一緒に開発するメンバーを募集中

僕もできる限りがんばって教えますので、Rustをやったことがない人も、やったことがないなぁと敬遠せず、ぜひ入社してもらえればと思います。

Rustをやったことがある人は、僕も教えてもらいたいので、ぜひ入社してもらえればと思っています。副業、アルバイト、インターンなど、職場体験的な感じでRust体験ができるので、そちらも検討してもらえればなと思っています。

最後にどういう感じかというと、本当にすごいスタンダードな感じで、フロントエンドはReactで書いていて、バックエンドは先ほど言ったとおりRustとactix-webを使って書いています。あとはサードパーティのいろいろなサービスをインテグレーションしてやっていますよという感じです。ぜひ入社を検討してもらえればうれしいなと思います。ありがとうございました。