[C++] CrowとVSCodeでWebAPIを作る
Crowは、C++でWebAPI等を作れる、サーバサイドWebフレームワークです。
今回はごくシンプルなWebAPIを作るまでをゴールとします。本記事は公式の情報にほぼ沿っているのみで、VSCodeの手引きを添えているのが追加の情報です。
以下ハローワールドの例で、軽量言語によくあるフレームワークの心地です。
#include "crow.h"
int main()
{
crow::SimpleApp app;
CROW_ROUTE(app, "/")([](){
return "Hello world";
});
app.port(18080).run();
}
サンプルコード
筆者の環境
devcontainerなので、Dockerが動けば環境は問いません。
ホスト
- Windows 11 + WSL2
- Docker for Windows 4.15.0
- Visual Studio Code 1.74.2
devcontainer内
- Crow (commit : 209f5ec67ddd7f0a5d80d0853d0527ded029034a)
- gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
VSCodeの拡張ではDev Containersをインストールします。
手順
VSCodeのdevcontainerを作り、その中で動かすことにします。
Crow環境構築手順をDockerfileで定義
適当な空のディレクトリにて、Dockerfileを書きます。公式の手引きに沿って環境構築しています。Crowはソースコードからビルドしました。
FROM ubuntu:22.04
ENV TZ=Asia/Tokyo
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt install -y --no-install-recommends \
git \
build-essential \
cmake \
libasio-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN git clone https://github.com/CrowCpp/Crow.git \
&& mkdir Crow/build \
&& cd Crow/build \
&& cmake .. -DCROW_BUILD_EXAMPLES=OFF -DCROW_BUILD_TESTS=OFF \
&& make -j$(nproc) \
&& make install \
&& make clean \
&& cd && rm -rf Crow
devcontainerの構築
続いてVSCodeをそのディレクトリで開いて、コマンドパレットから Add Dev Container Configuration Files… を選択します。
From Dockerfileを選択します。次のダイアログは選択せずOKでよいです。
すると .devcontainer/devcontainer.json
を作成してくれました。
このまま Reopen in container を押すと、docker buildでしばらく待たされたのち、devcontainerが立ち上がって準備完了です。
アプリケーションのコード
C++ソースコードを追加します。JSONのリクエストを受けて、足し算をして返すエンドポイントにしました(参考)。
#include <crow.h>
int main()
{
crow::SimpleApp app;
CROW_ROUTE(app, "/add_json")
.methods(crow::HTTPMethod::Post)([](const crow::request& req) {
auto x = crow::json::load(req.body);
if (!x)
return crow::response(400);
auto sum = x["a"].i() + x["b"].i();
std::ostringstream os;
os << sum;
return crow::response{os.str()};
});
app.port(80)
.multithreaded()
.run();
}
CMake
コンパイルは、コマンドを手打ちしてもよいですが、CMakeに頼ることにします。[1]
cmake_minimum_required(VERSION 3.20)
project(first_crow CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(${PROJECT_NAME} main.cpp)
find_package(Crow REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC Crow::Crow)
ビルド
$ mkdir build
$ cd build
$ cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: /workspaces/first_crow/build
$ make
Consolidate compiler generated dependencies of target first_crow
[ 50%] Building CXX object CMakeFiles/first_crow.dir/main.cpp.o
<command-line>: warning: ISO C++11 requires whitespace after the macro name
[100%] Linking CXX executable first_crow
[100%] Built target first_crow
cmakeは、構成を大きく変えない限りは1回だけ実行すればよく、以後のリビルドはmakeのみでOKです。
実行
build
ディレクトリの中に first_crow
というバイナリファイルができているはずです。
$ ./first_crow
(2022-12-23 21:07:35) [INFO ] Crow/master server is running at http://0.0.0.0:80 using 12 threads
(2022-12-23 21:07:35) [INFO ] Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs.
...
これでサーバーアプリケーションが起動しました。VSCodeのPORTSタブを見るとわかるはずです。
ホスト側で localhost:80
を叩けばこのWebAPIにリクエストできます。curlやPostmanなど何らかの方法で試してみてください。
$ curl -s -X POST http://localhost:80/add_json -d '{"a":1, "b":2}'
3
C++のサーバサイドWebフレームワークについて
最後にCrow以外も含めた状況を記しておきます。軽く調べたところ、以下3つが有力に思われました。
上から順に"しっかりした"仕様と思います。Oat++はよく作りこまれていて、一般には一番おすすめかもしれません(そのうち記事にするかも)。DrogonはWebフレームワークのベンチマークにて最近最上位を占めることで知られます。CrowはFlask等に似てコントローラクラスもない簡単な書き味が特徴です。
以下私見ですが、C++によるサーバサイドの実装は流行っておらず、処理速度はよほどでなければRust等の他の選択肢があるはずで、動機というとC/C++の資産活用が一番に来るのではと思います。お世辞にもサーバアプリケーション開発体験は今主流の他言語に及ばないので、C++で作る範囲はマイクロサービス等の形で最小化し、主要部分は別の言語で書くのが無難と考えます。そうだとすれば、あまりがっちり作っても仕方ないからCrowにしよう、というのは選択肢になり得るのかもしれません。
備考: コード補完設定
以下を導入して設定することで、VSCodeでのC++開発を効率化します。
.vscode
というディレクトリ(無ければ作成)の中に以下のような設定ファイルを置きました。
{
"C_Cpp.clang_format_style": "file",
"C_Cpp.default.cppStandard": "c++17",
"editor.defaultFormatter": "ms-vscode.cpptools",
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
}
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu17",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}
c_cpp_properties.json
の includePath
のところには、サードパーティライブラリ等で#includeの箇所がエラーになってしまう場合にそこにパスを追加すると良いです。
"C_Cpp.clang_format_style": "file"
に対応する、フォーマット定義ファイルを置きます。なお始めの---
は意味があり、書き間違いではありません。
---
BasedOnStyle: Microsoft
IndentWidth: 4
改行やスペースの有無等、設定できる項目は多岐にわたります。以下を参照ください。
-
Zennのシンタックスハイライトでは、なぜかtarget_link_librariesのところで意図せぬ改行ができてしまいます。XX::YY のようなコロン2個を書くとこうなります。 ↩︎
Discussion