Oat++を導入してHello Worldまで
Oat++
今回は、Oat++の導入とサンプルアプリケーションを動かした内容を書いてみました。
はじめる前に
ここで書いてある内容はGetting Startedにもだいたい載っている内容です。お急ぎの方は、そちらを見たほうが早いかもしれません。
利用環境
複数の環境でやっていますが、この記事を記載した際の環境を記しておきます。
- Ubuntu 20.04 LTS
- cmake 3.18.2
- g++ 9.3.0
上記が利用できる環境であれば、多くのプラットフォームで動くのは魅力ですね。未確認ですがWindowsでも動くそうです。
インストール
ますはOat++の導入に必要なものをパッケージから。cmakeでビルドするのでcmakeも追加しておきます。
$ sudo apt install build-essential git cmake
Oat++をgit clone
してビルドしてインストール。cmakeはハマらなければいいプロダクトなんですけどね。
$ git clone https://github.com/oatpp/oatpp.git
$ cd oatpp/
$ mkdir build
$ cd build
$ cmake ..
$ sudo make install
これでOat++の導入は終わりましたので、Webアプリケーションをビルドして起動してみましょう。
Hello World
Oat++のHello Worldっぽいoatpp-starterを利用して、Webアプリケーションをビルドします。
まずは適当なディレクトリでgit clone
しましょう。
$ git clone https://github.com/oatpp/oatpp-starter.git
cloneした中身はこんな感じ。
├── CMakeLists.txt //このプロジェクトのCMakeLists.txt
├── Dockerfile
├── LICENSE
├── README.md
├── azure-pipelines.yml
├── src
│ ├── App.cpp //main()があるところ
│ ├── AppComponent.hpp //サービスの定義、設定など
│ ├── controller
│ │ ├── MyController.cpp
│ │ └── MyController.hpp //コントローラーの定義
│ └── dto
│ └── DTOs.hpp //DTOの定義
├── test //テスト用ディレクトリ
│ ├── MyControllerTest.cpp
│ ├── MyControllerTest.hpp
│ ├── app
│ │ ├── MyApiTestClient.hpp
│ │ └── TestComponent.hpp
│ └── tests.cpp
└── utility
└── install-oatpp-modules.sh
cloneしたディレクトリに入り、cmakeでビルドします。
$ cd oatpp-starter/
$ mkdir build && cd build
$ cmake ..
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/hoge/tmp/oatpp-starter/build
cmakeが通ったら、同じディレクトリでmake。
$ make
Scanning dependencies of target my-project-lib
[ 14%] Building CXX object CMakeFiles/my-project-lib.dir/src/controller/MyController.cpp.o
[ 28%] Linking CXX static library libmy-project-lib.a
[ 28%] Built target my-project-lib
Scanning dependencies of target my-project-test
[ 42%] Building CXX object CMakeFiles/my-project-test.dir/test/tests.cpp.o
[ 57%] Building CXX object CMakeFiles/my-project-test.dir/test/MyControllerTest.cpp.o
[ 71%] Linking CXX executable my-project-test
[ 71%] Built target my-project-test
Scanning dependencies of target my-project-exe
[ 85%] Building CXX object CMakeFiles/my-project-exe.dir/src/App.cpp.o
[100%] Linking CXX executable my-project-exe
[100%] Built target my-project-exe
ビルドが成功すれば、同じbuildディレクトリ上にmy-project-exe
ができてるので起動します。
$ ./my-project-exe
I |2020-09-26 18:52:04 1601113924442374| MyApp:Server running on port 8000
書かれている http://localhost:8000/
にアクセスすると、以下のように表示されているでしょう。
ちょっとだけ解説
Web周りもそんなに詳しいわけではありませんが、各ソースの役割周りを。
- App.cpp
エントリーポイントとなるmain()から、サーバー起動を行うrun()を呼び出し、コントローラー(ここにアクセスしたらこうするとかの設定)とルーターの設定、後述するコンポーネントの設定の読み込みをしたら、server.run()でwebサーバーを起動する一連の処理。
お試し分であればいいと思いますが、システムとしてバックエンドで動作させるなら、シグナルやスレッド処理を入れそうなところ。
- AppComponent.hpp
アクセス用ポートの設定をまとめたコネクションプロバイダー、ルーター[2]の定義をまとめたコネクションハンドラー、DTO[3]などのオプジェクトマッピングをコンポーネントとして定義しています。
マクロ使いまくってるので判りづらいところも有りますが、これをApp.cppや後述のMyController.hppでバインドして、利用していると考えればよいでしょう。なんもわからん場合は定義系のファイルと覚えておけば。
- MyController.hpp
ルーターで結び付けられたENDPOINTに対しての処理を定義。このファイルの場合だと、
ENDPOINT("GET", "/", root) {
auto dto = MyDto::createShared();
dto->statusCode = 200;
dto->message = "Hello World!";
return createDtoResponse(Status::CODE_200, dto);
}
と、定義されているので、localhost:8000
にアクセスしたら、DTOに応答メッセージなどを詰め込んで、クライアントにお返ししますって処理を行ってます。
また、特に定義されてないところにアクセスした場合は404を自動的に返してくれます。
- DTOs.hpp
MyController.hppで応答メッセージに詰め込んだ、データ群を定義する場所。今回だと以下のようになっています。
DTO_INIT(MyDto, DTO) //DTOの定義をMyDtoとして定義
DTO_FIELD(Int32, statusCode); //ステータスコード
DTO_FIELD(String, message); //メッセージ
ステータスコードやメッセージのデータを定義したMyDtoを、前述のMyController.hppで呼び出して利用しています。簡単に書くと、データを転送用の器の定義でしょうか。
ちなみに、DTOを定義しなくてもメッセージをやり取りすることは可能ですが、実際にJSON Serialize/Deserialiseを行う場合や、ORMと連携してDBに登録する場合DTOを利用したほうが楽かと思います。
参考
すべて英語です。
- Getting Started
-
Starter Project
- oatpp/oatpp-starter:GitHubのレポジトリ
- High Level Overview:Oat++ APIの概要
- API Controller:APIコントローラーの解説
- Data Transfer Object (DTO):DTOの定義や使い方
おわりに
使ってみた感想としては、C++でWebフレームワークとかどんなもんなんでしょ。と過去にCでWebサーバーみたいなものを実装した経験もあるので、割と苦労するのかなと想いましたが、マクロ定義でメモリ管理などもひっくるめて定義していて、決まった内容のやり取りであればC++に強くなくても、実装できるように作られていて"The Rails Way"ぽさも感じました。
ただしここから外れると、C++の強みや弱みなどを意識しないといけないので、こうやりたいってことを、Oatppでどう実現するかという戦略をもって取り組むと作りやすいかなと思いました。
あと、Viewについては特に考えられていません。他のプロダクトと併せて使うのがいいという判断なのでしょうね。
Oat++、日本のユーザーもいるにはいるけど記事も少ない[4]し、あっても情報古いところもあるので、本編のようなインストールからHello World以外でも、もうちょっと濃いめの内容も書きたいのでまた時間を捻出します…
Discussion