• トップ
  • ブログ一覧
  • 【Controller編】最速のC++ Webフレームワーク「Drogon」を試してみた!
  • 【Controller編】最速のC++ Webフレームワーク「Drogon」を試してみた!

    広告メディア事業部広告メディア事業部
    2020.09.13

    IT技術

    Controller 編~最速のC++ Web フレームワーク「Drogon」を試してみる~

    最速の Web フレームワークとして注目を集めている「Drogon」。

    前回は、Drogon のインストールと動作確認を行いましたが、実用的な使い方までは紹介しきれませんでした。

    featureImg2020.09.11【環境構築編】最速のC++ Webフレームワーク「Drogon」を試してみた!Web フレームワーク「Drogon」とは?つい最近、TechEmpower が独自でベンチマークを計測したランキング...

    Drogon のコントローラについて学ぼう

    今回は、Drogon の「Controller (コントローラ)」について見ていきます。

    コントローラは、Web フレームワークの心臓部と言っても過言ではない超重要ポイントです。

    この記事で、しっかり理解しておきましょう!

    Controller とは?

    「コントローラ」は、URL リクエストを解析し、どういった処理をするか決定する Web アプリケーションのコアです。

    前回は、Drogon がサポートしている Controller の中で、最もシンプルなHttpSimpleController の紹介をしました。

    実用的なコントローラ「HttpController」

    今回は、皆さんにも馴染みのある、実用的なコントローラを紹介していきます。

    今回紹介するHttpController クラスは、URL パラメータなどを捌くためのコントローラです。

    HttpController の生成

    drogon_ctl コマンドで、同じように生成します。

    通常のコントローラ生成コマンドは-h オプションをつけた、以下のような構文で生成します。

    1$ drogon_ctl create controller -h <[namespace::]class_name>

    名前空間はなくても構いませんが、管理のしやすさと名前衝突を避けるために、何かしら定めた方が良いでしょう。

    Drogon の名前空間は URL にも反映される

    また、Drogon では、名前空間がそのまま URL にも反映されます。

    今回は公式ドキュメントに倣って、controller ディレクトリで以下のように作成しました。

    1$ drogon_ctl create controller -h demo::v1::User

    これで、今から作成するコントローラは全て「/demo/v1/user/{ルーティングしたパス}」というURLで処理されるようになります。

    ファイル生成

    コマンドを実行すると、「demo_v1_User」という名前の.h ファイル、.cc ファイルが生成されます。

    1#pragma once
    2#include <drogon/HttpController.h>
    3using namespace drogon;
    4namespace demo
    5{
    6    namespace v1
    7    {
    8        class User:public drogon::HttpController<User>
    9        {
    10          public:
    11            METHOD_LIST_BEGIN
    12            //use METHOD_ADD to add your custom processing function here;
    13            //METHOD_ADD(User::get,"/{2}/{1}",Get);//path is /demo/v1/User/{arg2}/{arg1}
    14            //METHOD_ADD(User::your_method_name,"/{1}/{2}/list",Get);//path is /demo/v1/User/{arg1}/{arg2}/list
    15            //ADD_METHOD_TO(User::your_method_name,"/absolute/path/{1}/{2}/list",Get);//path is /absolute/path/{arg1}/{arg2}/list
    16
    17            METHOD_LIST_END
    18            // your declaration of processing function maybe like this:
    19            // void get(const HttpRequestPtr& req,std::function<void (const HttpResponsePtr &)> &&callback,int p1,std::string p2);
    20            // void your_method_name(const HttpRequestPtr& req,std::function<void (const HttpResponsePtr &)> &&callback,double p1,int p2) const;
    21        };
    22    }
    23}
    1#include "demo_v1_User.h"
    2using namespace demo::v1;
    3//add definition of your processing function here

    モデル作成に見えるけど…

    HttpSimpleController とは、やや形式が異なっていますね。

    User というモデルを作っているように見えるかもしれませんが、これは単なるコントローラなので、User モデルは生成されません。

    URL によって表示を変える

    ここからは、Drogon の公式ドキュメントでは分かりにくい箇所を解説していきます。

    まずは、「/info/{userId}」でユーザ ID と名前を JSON で返す処理を実装してみましょう!

    ヘッダーファイルに宣言を記述

    まずは、ヘッダーファイルに宣言を書きます。

    1// demo_v1_User.h
    2#pragma once
    3#include <drogon/HttpController.h>
    4using namespace drogon;
    5namespace demo
    6{
    7    namespace v1
    8    {
    9        class User:public drogon::HttpController<User>
    10        {
    11          public:
    12            METHOD_LIST_BEGIN
    13
    14            // GETでアクセスされた場合、User::getInfo()に処理を投げる
    15            METHOD_ADD(User::getInfo,"/info/{1}",Get);
    16
    17            METHOD_LIST_END
    18
    19            // メソッドの宣言
    20            void getInfo(const HttpRequestPtr &req,
    21                         std::function<void (const HttpResponsePtr &)> &&callback,
    22                         std::string userId) const;
    23
    24        };
    25    }
    26}

    ソースファイルに処理を記述

    続いて、処理をソースファイルに書いていきます。

    1// demo_v1_User.cc
    2#include "demo_v1_User.h"
    3using namespace demo::v1;
    4//add definition of your processing function here
    5
    6void User::getInfo(const HttpRequestPtr &req,  // 必須
    7                   std::function<void (const HttpResponsePtr &)> &&callback,  // 必須
    8                   std::string userId  // URLパラメータ
    9                   ) const
    10{
    11    // LOG_DEBUGでコンソール上に、「いつ」「どの関数で」「どのファイルで」呼び出されたかが表示される
    12    LOG_DEBUG<<"User "<<userId<<" get his information";
    13
    14    // ~~本来であればここでトークンを参照したり、データベースからユーザIDをもとにデータを取得する処理が入る~~
    15
    16    Json::Value ret;    // JSONインスタンス
    17
    18    // JSONにデータを格納
    19    ret["result"]="ok";
    20    ret["user_name"]="Jack";
    21    ret["user_id"]=userId;
    22    ret["gender"]=1;
    23
    24    auto resp=HttpResponse::newHttpJsonResponse(ret);
    25    callback(resp);
    26}

    動作確認

    試しに、「http://localhost/demo/v1/user/info/12345」にアクセスしてみると、

    1{"gender":1,"result":"ok","user_id":"12345","user_name":"Jack"}

    と返ってくるはずです。

    コンソール表示も確認

    さらにはコンソールでは、デバッグ用の出力で、

    120200805 05:52:10.897361 UTC 832966 DEBUG [getInfo] User 12345 get his information - demo_v1_User.cc:11

    のように表示されているはずです。

    Drogon のデバッグ出力は C++ 標準出力と同じ

    C++では、標準出力をstd::cout << "Hello" << std::endl; のように記述します。

    Drogon のデバッグ出力も同じような実装をしており、普段 C++を使っている人なら難なく扱えると思います。

    GET パラメータ処理も同じ

    例えば「/info?userId={xxx}」のような URL も、同様に処理ができます。

    1METHOD_ADD(User::getInfo,"/info?userId={1}",Get);

    のようにするだけです。

    URL パラメータの記法

    先ほどの例では、全て{1}, {2} といった書き方をしていましたが、他にもちょっとした決まりがあります。

    1. {} : 通常のパラメータマッピング。
    2. {1}, {2}  : パラメータの番号付。
    3. {anything} : {} と同じ。可読性向上のために何かしら文字列を入れることができる。
    4. {1:anything}, {2:xxx} : {1}, {2} と同じ。可読性向上のためのもの。

    公式では、3番目と4番目の記法が推奨されています。

    これらのことを踏まえると、以下の URL クエリは全て同義であることが分かりますね。

    1. "/users/{}/books/{}"
    2. "/users/{}/books/{2}"
    3. "/users/{user_id}/books/{book_id}"
    4. "/users/{1:user_id}/books/{2}"

    Drogon の便利な機能「URL 正規表現」

    Drogon のコントローラでは、他にも多くの便利な機能が提供されています。

    今回は、「URL 正規表現」についてご紹介します。

    Multiple Path Mapping

    以下のようなルーティングであれば、様々な URL リクエストを1つのコントローラに集約させることができます。

    1// "/users/"を接頭辞としたURL全て
    2ADD_METHOD_TO(UserController::handler1,"/users/.*",Post); 
    3
    4// "/{文字列}/{数字}"のURL全て
    5ADD_METHOD_TO(UserController::handler2,"/{name}/[0-9]+",Post);

    Regular Expression (Regex: 正規表現)

    もっと細かく指定する場合は、「正規表現」を使いましょう。

    1// "/users/"を接頭辞とするURLをhandler1へ
    2ADD_METHOD_VIA_REGEX(UserController::handler1,"/users/(.*)",Post); 
    3
    4// "/abcde5"のような、末尾が数字となるURLをhandler2へ
    5ADD_METHOD_VIA_REGEX(UserController::handler2,"/.*([0-9]*)",Post); 
    6
    7// "/data"で始まらないURLをhandler3へ
    8ADD_METHOD_VIA_REGEX(UserController::handler3,"/(?!data).*",Post);

    これを上手く使えば、全ての URL を漏れなくユーザに提供できるようになります。

    ただし、くれぐれも競合しないよう注意して下さい。

    View 編へつづく!

    今回は、Drogon のコントローラの扱いについて簡単に紹介しました。

    これで、シンプルな WebAPI であれば作成できそうですね。

    次回は、「Web アプリケーションの View の扱い」について解説していきます!

    View 編はこちら!

    featureImg2020.09.15【View編】最速のC++ Webフレームワーク「Drogon」を試してみた!View 編~最速のC++ Webフレームワーク「Drogon」を試してみた!~最速の Web フレームワークとして注...

    こちらの記事もオススメ!

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
    featureImg2020.07.27IT・コンピューターの歴史特集IT・コンピューターの歴史をまとめていきたいと思います!弊社ブログにある記事のみで構成しているため、まだ「未完成状態」...
    featureImg2020.08.04エンジニアの働き方 特集社員としての働き方社員としてのエンジニアの働き方とは?ライトコードのエンジニアはどんな働き方をしてるのか、まとめたいと...

    広告メディア事業部

    広告メディア事業部

    おすすめ記事