Oat++を導入してHello Worldまで

公開:2020/09/26
更新:2020/09/26
9 min読了の目安(約5800字TECH技術記事

Oat++

Oat++[1]はC++のWebフレームワークです。

今回は、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を利用したほうが楽かと思います。

参考

すべて英語です。

おわりに

使ってみた感想としては、C++でWebフレームワークとかどんなもんなんでしょ。と過去にCでWebサーバーみたいなものを実装した経験もあるので、割と苦労するのかなと想いましたが、マクロ定義でメモリ管理などもひっくるめて定義していて、決まった内容のやり取りであればC++に強くなくても、実装できるように作られていて"The Rails Way"ぽさも感じました。

ただしここから外れると、C++の強みや弱みなどを意識しないといけないので、こうやりたいってことを、Oatppでどう実現するかという戦略をもって取り組むと作りやすいかなと思いました。

あと、Viewについては特に考えられていません。他のプロダクトと併せて使うのがいいという判断なのでしょうね。

Oat++、日本のユーザーもいるにはいるけど記事も少ない[4]し、あっても情報古いところもあるので、本編のようなインストールからHello World以外でも、もうちょっと濃いめの内容も書きたいのでまた時間を捻出します…

脚注
  1. "Oatpp"と表記される場合もあります。ググらビリティ… ↩︎

  2. リクエストと処理するメソッド(今回はENDPOINT)とを結びつける機能 ↩︎

  3. Data Transfer Object。データの格納・取り出しをやりやすくする仕組み(デザインパターン)。Javaやってた人はわかるかと。 ↩︎

  4. Qiitaにもないしねえ…欲しい情報がチャット上だけだったこともあります… ↩︎