C++BuilderでRESTfulなWebBrokerを構築する[JAPAN]

Posted by on in Programming

C++Builder Professional以上にはWebBrokerが付いています。

そのWebBrokerを使いRESTfulなリソースサフィックス形式のURIを受け取り解釈する事が可能です。

TWebModuleにはActionを持っていてresourceは切れますが自前で実装しています。

今回試したのはWebBrokerスタンドアロン(Win64)です。

TWebModule側にはDB接続テストする為のFireDACのコンポーネントを配置しています。

DBはMySQLです

TWebModule1に入ってくるTWebRequest Request->PathInfoをResource/Suffixとして解釈します。

 

[PathInfoを"/"で分解してstd::vector<UnicodeString>に入れる]

////
std::vector<UnicodeString> __fastcall TWebModule1::path_to_vector(String path_)
{
    std::vector<UnicodeString> vector_path;
    std::wstringstream wss{path_.w_str()};
    std::wstring path_item;
    while (getline(wss, path_item , L'/'))
        if (!path_item.empty())
        {
            vector_path.push_back(path_item.c_str());
        }
    return vector_path;
}

 

[それぞれのリソース用メンバー関数を作ります]

////
    //resource1
    void __fastcall WebModule1WebActionResource1(TObject *Sender, TWebRequest *Request,
          TWebResponse *Response, bool &Handled, std::vector<UnicodeString>& path_);
    //resource2
    void __fastcall WebModule1WebActionResource2(TObject *Sender, TWebRequest *Request,
          TWebResponse *Response, bool &Handled, std::vector<UnicodeString>& path_);

 

[リソースに合わせて関数をstd::mapで登録します]

///
    //This std::map is resource management.
    std::map<String, TWebModuleHandlerAction>>resource_action_{
        std::make_pair( "resource1", WebModule1WebActionResource1),
        std::make_pair( "resource2", WebModule1WebActionResource2)
    };

Lambdaやstd::functionでもいいのですが今回は単純にusingで関数ポインタにしました。

////
using TWebModuleHandlerAction = void __fastcall (__closure *)(
	TObject *Sender, TWebRequest *Request, TWebResponse *Response, bool &Handled, std::vector<UnicodeString>& path_);

 

[WebBrokerのデフォルトで通る関数でPathInfoを解釈しstd::mapに存在する関数をコールします]

////
void __fastcall TWebModule1::WebModule1DefaultHandlerAction(TObject *Sender, TWebRequest *Request,
          TWebResponse *Response, bool &Handled)
{
    //Main function.
    //Convert Request->PathInfo to std::vector.
    auto v_path = path_to_vector(Request->PathInfo);
 
    (v_path.size() > 0)?
        //If the resource name exists, call the function that has been registered.
        (resource_action_.at(*(v_path.begin())))(Sender, Request, Response, Handled, v_path):
        Response->Content =
        "<html>"
        "<head><title>Web Server Application</title></head>"
        "<body>Web Server Application</body>"
        "</html>";
}

 

[登録した二つのメンバー関数です]

////
void __fastcall TWebModule1::WebModule1WebActionResource1(
    TObject *Sender, TWebRequest *Request,
    TWebResponse *Response, bool &Handled, std::vector<UnicodeString>& path_)
{
    std::unique_ptr<TJSONObject> jo_{std::make_unique<TJSONObject>()};
    UnicodeString out="none";
    if (path_.size() > 1) {
        auto pos_ = StrToIntDef(path_.at(1), 0);
        FDQuery1->SQL->Text = Format("select * from t_MotoGP where position = %d", ARRAYOFCONST((pos_)));
        FDQuery1->Active = true;
        while (! FDQuery1->Eof)
        {
            jo_->AddPair("racer_name", FDQuery1->FieldByName("racer_name")->AsString);
            FDQuery1->Next();
        }
        FDQuery1->Active = false;
    }
    Response->Content = jo_->ToJSON();
}
 
void __fastcall TWebModule1::WebModule1WebActionResource2(
    TObject *Sender, TWebRequest *Request,
    TWebResponse *Response, bool &Handled, std::vector<UnicodeString>& path_)
{
    std::unique_ptr<TJSONArray> ja_{std::make_unique<TJSONArray>()};
    UnicodeString out;
    TJSONObject* jo_;
    int iCount = 0;
    for (auto s: path_)
    {
        jo_ = new TJSONObject();
        jo_->AddPair(Format("item_%d", ARRAYOFCONST((iCount))), s);
        ja_->AddElement(jo_);
        iCount++;
    }
    Response->Content = ja_->ToJSON();
}

 

[結果]

http://localhost:8080/resource1/1

resource1はMySQL DB接続をしています

 

 

http://localhost:8080/resource2/japan/America/2017

resource2はサフィックスに入った文字をJSONでエコーするだけの処理です

 

[gistにコードをアップしています。]

https://gist.github.com/mojeld/63592be8f6c371116f2145b37c2a54aa

 



About
Gold User, No rank,
Delphi / C++Builder blogger

Comments

Check out more tips and tricks in this development video: