C++BuilderでRESTfulなWebBrokerを構築する[JAPAN]
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


Comments
-
Please login first in order for you to submit comments