• トップ
  • ブログ一覧
  • 【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エンジニアの働き方 特集社員としての働き方社員としてのエンジニアの働き方とは?ライトコードのエンジニアはどんな働き方をしてるのか、まとめたいと...

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    広告メディア事業部

    広告メディア事業部

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background