English Русский 中文 Español Deutsch
preview
Connexusの本体(第4回):HTTP本体サポートの追加

Connexusの本体(第4回):HTTP本体サポートの追加

MetaTrader 5 | 7 1月 2025, 08:59
67 0
joaopedrodev
joaopedrodev

はじめに

この記事は、Connexusと呼ばれるライブラリを構築する連載の続きです。最初の記事では、WebRequest関数の基本的な操作方法を理解し、それぞれのパラメータについて学んだうえで、この関数の使用例と、その際に直面する課題を示すサンプルコードを作成しました。前回の記事では、リクエストの仕組みやヘッダの役割、さらにヘッダを使用してリクエストを作成する方法を学び、ライブラリ内で異なるヘッダに対応する機能を開発しました。

API開発において、クライアントとサーバー間の通信はHTTPリクエストを通じて重要な情報を送受信します。ヘッダがこの通信の「封筒」に例えられるなら、本体(ボディ)は「手紙」そのものであり、送信する実際のデータが含まれています。本日の記事では、HTTPリクエストにおける本体の役割とその重要性、そしてConnexusを用いて本体を適切に設定する方法について詳しく解説します。それでは始めましょう。


HTTPの本体とは何か?

HTTPプロトコルにおいて、リクエスト(要求)やレスポンス(応答)の本体は、送受信される実際のコンテンツを指します。簡単に言えば、本体はサーバーに送りたいデータやサーバーから受け取りたいデータが格納される場所です。本体は、POST、PUT、PATCHといったタイプのリクエストの主要な構成要素であり、フォームデータやJSON、XMLのような構造化データ、さらにはファイルといった情報を送信する際に使用されます。この連載では、API利用時に最も一般的に使用されるJSON形式に焦点を当てますが、他の形式でもデータを送信できることを忘れないでください。

一方、GETタイプのリクエストでは通常、本体が存在しません。これは、このリクエストがデータを「取得」するために使われ、データを「送信」する目的ではないためです。この場合、サーバーはリクエストに対して通常、本体にリクエストされた結果を含むレスポンスを返します。しかし、POSTリクエストでは本体が不可欠です。本体を通じてデータがサーバーに送信され、サーバー側で処理がおこなわれるためです。このタイプのリクエストに対し、サーバーがレスポンスとして別の本体を返す場合もあれば、返さない場合もあります。

HTTP本体は、リクエストの種類に応じて、クライアントからサーバー、あるいはその逆方向に情報を送信するために使用されます。データの作成、更新、削除といった操作には欠かせない存在です。本体の主な役割は、サーバーが処理する必要のある「実際のコンテンツ」を運ぶことです。本体がなければ、HTTP通信は単なる情報の取得要求に限定され、複雑なデータの送信や高度な操作を実行することは不可能です。

HTTP通信における本体の役割を理解したところで、リクエストで本体を正しく使用する方法を知ることが重要です。送信するデータの種類によって、本体はJSON、XML、バイナリデータ(ファイルアップロードの場合など)など、さまざまな形式を取ることができます。それでは、いくつかの具体例を見てみましょう。

  1. JSON本体:JSON (JavaScript Object Notation)形式は、最近のアプリケーション、特にREST APIでは最も一般的なものです。軽量で読みやすく、構造化データの伝送に最適で、MQL5でHTTPを使用する際に最も広く使用される形式となります。リクエスト本体でJSONがどのように使われるか見てみましょう。

    {
      "type": "BUY",
      "symbol": "EURUSD",
      "price": 1.09223
      "volume": 0.01
      "tp": 1.09233
      "sl": 1.09213
    }

    この例では、トランザクションデータをサーバーに送信しています。サーバーはデータを受信して処理し、データベースに保存して、口座トランザクションのパフォーマンスメトリクスのダッシュボードを生成することもできるし、単にトランザクションデータを他の口座に再送信して、トランザクションコピーシステムを作成することもできます。この本体を使うには、ヘッダでコンテンツタイプがJSONであることを指定しなければなりません。

    Content-Type: application/json

  1. 本文:HTTPリクエストでデータを送るもう1つの一般的な方法は、プレーンテキスト形式です。この形式はシンプルであるため有利です。サーバーが送信内容をサポートしている限り、多くのルールや慣習に従うことなく、送信したい内容を書くだけで済みます。大量のデータを整理するのが難しいので、データを送信するのにはお勧めできません。このシナリオでは、最も推奨される形式はJSONです。プレーンテキストの例を見てみましょう。

    This is a plain text example

    ここでは、フォームフィールドは連結され、「&」で区切られ、各値には特定のキーが割り当てられています。この形式を使用するには、ヘッダを次のように設定する必要があります。

    Content-Type: application/text-plain

    これは最も古い形式のひとつだが、今でもさまざまな用途で広く使われています。私たちのConnexusライブラリはこのコンテンツタイプをサポートし、開発者が使用ケースに最も適したアプローチを選択できるようにします。


HTTPリクエストに本体を追加する

リクエストの本体にJSONを送信し、サーバーがそれを正しく受信したかどうかをチェックする実際の例を見てみましょう。このチェックをおこなうためには、以前の記事ですでに紹介したを引き続き使用します。最初から、Experts/Connexus/Test/TestBody.mq5フォルダにTestBody.mq5という別のファイルを作成し、前回の記事で使用したシンプルなポストリクエストを追加します。この記事で使用したファイルはすべて末尾に添付してあります。

//+------------------------------------------------------------------+
//|                                                     TestBody.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Connexus/Data/Json.mqh>
#include <Connexus/URL/URL.mqh>
#include <Connexus/Header/HttpHeader.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- URL
   CURL url;
   url.Parse("https://httpbin.org");
   url.Path("post");
   
   //--- Data to be sent
   string method = "POST";
   char body_send[];
   
   //--- Headers that will be sent separated by "\n"
   CHttpHeader headers_send;
   headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)");
   headers_send.Add("Content-Type","application/json");
   
   //--- Data that will be received
   char body_receive[];
   string headers_receive;
   
   //--- Send request
   int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive);
   
   //--- Show response
   Print("Respose: ",CharArrayToString(body_receive));
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

リクエストの本体は、char型の配列であるbody_send変数に存在しなければなりません。文字列はJSONやテキストを送信するのに理想的なのに、なぜchar[]ではなく文字列型にしないのか、と疑問に思うかもしれません。柔軟性、パフォーマンス、互換性に関連するいくつかの理由からです。詳しい理由は以下の通りです。

  • データ型の柔軟性:HTTPリクエストの本体には、テキスト、JSON、バイナリ(ファイル、画像)、その他の形式など、さまざまなタイプのデータを含めることができます。char配列を使うことで、テキストかバイナリかに関係なく、どのようなタイプのデータでも受け入れることができます。本体にファイル(画像、音声など)が含まれている場合、それをバイト配列として操作する必要があります。文字列は純粋なテキストデータに対してのみ有効であるため、この関数の使用はコンテンツがバイナリであるシナリオに限定されます。
  • パフォーマンス:char配列は、低レベルのデータ操作においてより効率的です。動的な文字列管理(メモリの割り当てや再割り当てなど)のオーバーヘッドを伴わないため、ネットワーキングコードをハードウェアに近いところで動作させることができ、大容量のファイル転送や低レイテンシのリクエストなど、高いパフォーマンスが要求されるアプリケーションには不可欠です。大きな画像ファイルを含むリクエストを送信する場合、char配列を使用することで、バイナリコンテンツを文字列に変換する必要がなくなり、CPUサイクルを節約できます。
  • HTTPプロトコルの互換性:HTTPプロトコルは、ネットワーク上でデータを送信する際、バイトを直接扱います。char配列(これはバイト列である)の方が、このプロトコルの低レベルな動作をよりよく反映しています。したがって、char配列を使用することで、HTTPリクエスト機能は、ネットワークレベルでのデータの扱い方と伝送方法に合わせることができます。

HTTPリクエストの本体にchar配列を使うことは、特にバイナリデータや大量のデータを含むシナリオにおいて、優れた柔軟性、パフォーマンス、互換性を提供します。この関数は、最も基本的な形式(バイト)のデータを直接扱うことができ、テキストデータにより適した文字列を扱う際のオーバーヘッドや制限を避けることができます。

StringToCharArray()関数を使用します。この関数について、ドキュメントに何が書かれているか調べてみましょう。

パラメータ

詳細
text_string
string
コピーする文字列
array[]
char[]
uchar型の配列
start
int
コピー開始位置(デフォルト:0)
count
int
コピーする配列要素の数。結果の文字列の長さを定義します。デフォルト値は-1であり、これは配列の終端まで、つまり端末0までコピーすることを意味します。端末0も受信者配列にコピーされます。この場合、必要に応じて動的配列のサイズを文字列のサイズまで増やすことができます。動的配列のサイズが文字列の長さを超える場合、配列のサイズは縮小されません。
codepage
uint コードページの値。MQL5では、文字列変数をchar型配列に変換する場合、またはその逆の場合、デフォルトでWindowsオペレーティングシステムの現在のANSI (CP_ACP)に対応するエンコーディングが使用されます。異なるタイプのエンコーディングを指定したい場合は、このパラメータで設定することができます。

以下の表は、最も人気のあるコードページの内部定数の一覧です。未指定のコードページは、対応するコードページを使って指定することができます。

定数
詳細
CP_ACP
0
現在のWindows ANSIコードページ
CP_OEMCP
1 現在のシステムOEMコードページ
CP_MACCP
2 現在のシステムMacintoshコードページ。この値は、主に以前に作成されたプログラムコードで使用されていました。最近のMacintoshコンピュータではエンコードにユニコードが使用されているため使用されていません。
CP_THREAD_ACP
3 現在のスレッドのWindows ANSIコードページ
CP_SYMBOL
42 記号コードページ
CP_UTF7
65000 UTF-7のコードページ
CP_UTF8
65001 UTF-8のコードページ

ほとんどのAPIでは、電子メールやWebページなどの標準的なエンコーディングタイプであるUTF8を使用します。それでは、UTF8エンコーディングに従ったjson形式の本体を追加してみましょう。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Data to be sent
   string method = "POST";
   CJson body;
   body["type"] = "BUY";
   body["symbol"] = "EURUSD";
   body["price"] = 1.09223;
   body["volume"] = 0.01;
   body["tp"] = 1.09233;
   body["sl"] = 1.09213;
   //--- {"price": 1.09223,"sl": 1.09213,"symbol": "EURUSD","tp": 1.09233,"type": "BUY","volume": 0.01}
   
   //--- Char that will be sent
   char body_send[];
   
   //--- Convert string to char (UTF8)
   StringToCharArray(body.Serialize(),body_send,0,WHOLE_ARRAY,CP_UTF8);
   
   //--- Show char array
   ArrayPrint(body_send);
         
   return(INIT_SUCCEEDED);
  }

このコードを実行すると、次がツールボックスに表示されます。

ツールボックス|エキスパート

配列の最後の位置には値「0」があることに注意してください。これは、リクエスト本文を読み取るときにサーバーにとって問題になる可能性があります。これを避けるために、ArrayRemove()関数とArraySize()関数を使用して配列の最後の位置を削除します。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Data to be sent
   string method = "POST";
   CJson body;
   body["type"] = "BUY";
   body["symbol"] = "EURUSD";
   body["price"] = 1.09223;
   body["volume"] = 0.01;
   body["tp"] = 1.09233;
   body["sl"] = 1.09213;
   //--- {"price": 1.09223,"sl": 1.09213,"symbol": "EURUSD","tp": 1.09233,"type": "BUY","volume": 0.01}
   
   //--- Char that will be sent
   char body_send[];
   
   //--- Convert string to char (UTF8)
   StringToCharArray(body.Serialize(),body_send,0,WHOLE_ARRAY,CP_UTF8);
   ArrayRemove(body_send,ArraySize(body_send)-1);
   
   //--- Show char array
   ArrayPrint(body_send);
         
   return(INIT_SUCCEEDED);
  }

再度実行すると、ツールボックスに以下が表示されます。

ツールボックス|エキスパート

さて、この小さなファインチューニングを解決したところで、実際にhttpリクエストにこの本体を追加してみましょう。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- URL
   CURL url;
   url.Parse("https://httpbin.org");
   url.Path("post");
   
   //--- Data to be sent
   string method = "POST";
   CJson body;
   body["type"] = "BUY";
   body["symbol"] = "EURUSD";
   body["price"] = 1.09223;
   body["volume"] = 0.01;
   body["tp"] = 1.09233;
   body["sl"] = 1.09213;
   char body_send[];
   StringToCharArray(body.Serialize(),body_send,0,WHOLE_ARRAY,CP_UTF8);
   ArrayRemove(body_send,ArraySize(body_send)-1);
   
   //--- Headers that will be sent separated by "\n"
   CHttpHeader headers_send;
   headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)");
   headers_send.Add("Content-Type","application/json");
   
   //--- Data that will be received
   char body_receive[];
   string headers_receive;
   
   //--- Send request
   int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive);
   
   //--- Show response
   Print("Respose: ",CharArrayToString(body_receive));
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

このコードを実行すると、httpbinから次のようなレスポンスが返ってきます。

Respose: {
  "args": {}, 
  "data": "{\"type\":\"BUY\",\"symbol\":\"EURUSD\",\"price\":1.09223000,\"volume\":0.01000000,\"tp\":1.09233000,\"sl\":1.09213000}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Accept-Language": "pt,en;q=0.5", 
    "Content-Length": "103", 
    "Content-Type": "text/plain", 
    "Host": "httpbin.org", 
    "User-Agent": "Connexus/1.0 (MetaTrader 5 Terminal)", 
    "X-Amzn-Trace-Id": "Root=1-67081b9c-3def4b1527d04edc1511cc6b"
  }, 
  "json": {
    "price": 1.09223, 
    "sl": 1.09213, 
    "symbol": "EURUSD", 
    "tp": 1.09233, 
    "type": "BUY", 
    "volume": 0.01
  }, 
  "origin": "189.74.63.39", 
  "url": "https://httpbin.org/post"
}

2つの興味深い点に注目してください。1つ目は、「data」フィールドに、本文で送信したJSONが文字列形式で含まれていることです。これは、サーバーが送信されたデータを受信して​​正しく解釈できたことを意味します。もう1つ注目すべき点は、「json」フィールドに送信したJSONが含まれていることで、サーバーがデータを正しく受信したことが改めて示されています。完璧に機能しています。


CHttpBodyクラスの作成

本体がどのように機能し、何のためにあり、どのように使うかを理解したところで、リクエスト本体を扱うクラスをConnexusライブラリに作りましょう。このクラスの名前はCHttpBodyで、本体を操作するメソッドを持ち、データの追加、更新、削除ができます。また、使用するエンコーディングも定義できるようになります(デフォルトはUTF8)。

Include/Connexus/Header/HttpBody,mqhフォルダにHttpBody.mqhという新しいファイルを作成します。ファイルを作成する際、最初はこのようになります。

//+------------------------------------------------------------------+
//|                                                     HttpBody.mqh |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| class : CHttpBody                                                |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpBody                                          |
//| Heritage    : No heritage                                        |
//| Description : Responsible for organizing and storing the body of |
//|               a request.                                         |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpBody
  {
public:
                     CHttpBody(void);
                    ~CHttpBody(void);

  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpBody::CHttpBody(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CHttpBody::~CHttpBody(void)
  {
  }
//+------------------------------------------------------------------+

クラスのprivateプロパティを定義しましょう。

  • m_body:リクエスト本体をchar配列で格納する
  • m_codepage:定義されたエンコーディングを保存するために使用する
//+------------------------------------------------------------------+
//| Include the file CJson class                                     |
//+------------------------------------------------------------------+
#include "../Data/Json.mqh"
//+------------------------------------------------------------------+
//| class : CHttpBody                                                |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpBody                                          |
//| Heritage    : No heritage                                        |
//| Description : Responsible for organizing and storing the body of |
//|               a request.                                         |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpBody
  {
private:
   
   char              m_body[];                           // Will store the request body as a char array
   uint              m_codepage;                         // Used to store the defined encoding
  };;
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpBody::CHttpBody(void)
  {
   m_codepage = CP_UTF8;
  }
//+------------------------------------------------------------------+

次に、リクエスト本体を処理するためのpublicメソッドを定義してみましょう。

  • 本体にデータを追加する
    • AddString(string data):リクエスト本体にテキスト文字列を追加します。
    • AddJson(CJson data):JSON形式のデータを本体に追加します。これには、JSONオブジェクトを形式された文字列に変換することが含まれる場合があります。
    • AddBinary(char &data[]):バイナリデータ (ファイルなど) をリクエスト本体に直接追加できるようにします。
  • 本体からデータを削除する
    • Clear(void):リクエスト本体からすべての内容を削除し、ゼロから始めることができるようにします。
  • 本体のコンテンツを取得する
    • GetAsString(void):リクエスト本体を文字列で返します。
    • GetAsJson(void):リクエスト本体をJSONオブジェクトに変換します。本体に構造化データが含まれている場合に便利です。GetAsChar(char &body[]) :バイナリデータを扱う際に便利なバイト配列として本体を返します。
  • 本体サイズを確認する
    • GetSize(void):リクエスト本体のサイズを、通常はバイト数で返します。
  • 符号化
    • GetCodePage(void):定義されたコードページを返します。
    • SetCodePage(uint codepage):使用するコードページを設定します。

これらのメソッドをクラスに追加してみましょう。

//+------------------------------------------------------------------+
//| class : CHttpBody                                                |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpBody                                          |
//| Heritage    : No heritage                                        |
//| Description : Responsible for organizing and storing the body of |
//|               a request.                                         |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpBody
  {
private:
   
   char              m_body[];                           // Will store the request body as a char array
   uint              m_codepage;                         // Used to store the defined encoding
   
public:
                     CHttpBody(void);
                    ~CHttpBody(void);

   //--- Add data to the body
   void              AddString(string data);             // Adds a text string to the request body
   void              AddJson(CJson &data);               // Adds data in JSON format to the body
   void              AddBinary(char &data[]);            // Allows you to add binary data
   
   //--- Clear the body
   void              Clear(void);                        // Remove all body content
   
   //--- Gets the body content
   string            GetAsString(void);                  // Returns the request body as a string
   CJson             GetAsJson(void);                    // Converts the request body into a JSON object, useful when the body contains structured data
   void              GetAsBinary(char &body[]);          // Returns the body as an array of bytes, useful for working with binary data
   
   //--- Size in bytes
   int               GetSize(void);                      // Returns the size of the request body, usually in bytes
   
   //--- Codepage
   uint              GetCodePage(void);                  // Returns the defined codepage
   void              SetCodePage(uint codepage);         // Defines the codepage to be used
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpBody::CHttpBody(void)
  {
   m_codepage = CP_UTF8;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CHttpBody::~CHttpBody(void)
  {
  }
//+------------------------------------------------------------------+
//| Adds a text string to the request body                           |
//+------------------------------------------------------------------+
void CHttpBody::AddString(string data)
  {
   StringToCharArray(data,m_body,this.GetSize()-1,WHOLE_ARRAY,m_codepage);
   ArrayRemove(m_body,this.GetSize()-1);
  }
//+------------------------------------------------------------------+
//| Adds data in JSON format to the body                             |
//+------------------------------------------------------------------+
void CHttpBody::AddJson(CJson &data)
  {
   this.AddString(data.Serialize());
  }
//+------------------------------------------------------------------+
//| Allows you to add binary data                                    |
//+------------------------------------------------------------------+
void CHttpBody::AddBinary(char &data[])
  {
   ArrayCopy(m_body,data);
  }
//+------------------------------------------------------------------+
//| Remove all body content                                          |
//+------------------------------------------------------------------+
void CHttpBody::Clear(void)
  {
   ArrayFree(m_body);
  }
//+------------------------------------------------------------------+
//| Returns the request body as a string                             |
//+------------------------------------------------------------------+
string CHttpBody::GetAsString(void)
  {
   return(CharArrayToString(m_body,0,WHOLE_ARRAY,m_codepage));
  }
//+------------------------------------------------------------------+
//| Converts the request body into a JSON object, useful when the    |
//| body contains structured data                                    |
//+------------------------------------------------------------------+
CJson CHttpBody::GetAsJson(void)
  {
   CJson json;
   json.Deserialize(this.GetAsString());
   return(json);
  }
//+------------------------------------------------------------------+
//| Returns the body as an array of bytes, useful for working with   |
//| binary data                                                      |
//+------------------------------------------------------------------+
void CHttpBody::GetAsBinary(char &body[])
  {
   ArrayCopy(body,m_body);
  }
//+------------------------------------------------------------------+
//| Returns the size of the request body, usually in bytes           |
//+------------------------------------------------------------------+
int CHttpBody::GetSize(void)
  {
   return(ArraySize(m_body));
  }
//+------------------------------------------------------------------+
//| Returns the defined codepage                                     |
//+------------------------------------------------------------------+
uint CHttpBody::GetCodePage(void)
  {
   return(m_codepage);
  }
//+------------------------------------------------------------------+
//| Defines the codepage to be used                                  |
//+------------------------------------------------------------------+
void CHttpBody::SetCodePage(uint codepage)
  {
   m_codepage = codepage;
  }
//+------------------------------------------------------------------+

これらのメソッドは単純明快で、最も大きなものでも3行しかありません。しかし、そのシンプルさに惑わされてはいけません。これらは非常に便利で、ライブラリのコード行数の削減に大きな影響を与えます。コードがスリムになるだけでなく、ライブラリをより使いやすく、メンテナンスしやすくします。


テスト

テストに移り、クラスの振る舞いを見てみましょう。冒頭と同じファイル、TestBody.mq5を使います。

{
  "type": "BUY",
  "symbol": "EURUSD",
  "price": 1.09223
  "volume": 0.01
  "tp": 1.09233
  "sl": 1.09213
}

このテストでは、このJSONをPOSTリクエストの本体に追加します。そのデータでjsonオブジェクトを作成します。

CJson body_json;
body_json["type"] = "BUY";
body_json["symbol"] = "EURUSD";
body_json["price"] = 1.09223;
body_json["volume"] = 0.01;
body_json["tp"] = 1.09233;
body_json["sl"] = 1.09213;

CHttpBodyクラスのインスタンスを作成し、その中にこのJSONを追加してみましょう。

CHttpBody body;
body.AddJson(body_json);

できました。あとはこれをchar配列に変換するだけです。

//--- Body in char array
char body_send[];
body.GetAsBinary(body_send);

簡単です。JSONをリクエストに追加するだけです。これをchar配列に変換する最後のステップは、ライブラリの最後には必要ありません。まだ開発中であるため、すべてを「手作業」でおこないます。最終的にコードは次のようになります。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- URL
   CURL url;
   url.Parse("https://httpbin.org");
   url.Path("post");
   
   //--- Data to be sent
   string method = "POST";
   CJson body_json;
   body_json["type"] = "BUY";
   body_json["symbol"] = "EURUSD";
   body_json["price"] = 1.09223;
   body_json["volume"] = 0.01;
   body_json["tp"] = 1.09233;
   body_json["sl"] = 1.09213;
   CHttpBody body;
   body.AddJson(body_json);
   
   //--- Body in char array
   char body_send[];
   body.GetAsBinary(body_send);
   
   //--- Headers that will be sent separated by "\n"
   CHttpHeader headers_send;
   headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)");
   headers_send.Add("Content-Type","application/json");
   
   //--- Data that will be received
   char body_receive[];
   string headers_receive;
   
   //--- Send request
   int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive);
   
   //--- Show response
   Print("Respose: ",CharArrayToString(body_receive));
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
実行すると以下のような結果になります。
Respose: {
  "args": {}, 
  "data": "{\"type\":\"BUY\",\"symbol\":\"EURUSD\",\"price\":1.09223000,\"volume\":0.01000000,\"tp\":1.09233000,\"sl\":1.09213000}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Accept-Language": "pt,en;q=0.5", 
    "Content-Length": "103", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "Connexus/1.0 (MetaTrader 5 Terminal)", 
    "X-Amzn-Trace-Id": "Root=1-670902d1-5a796b1e1fe2053f18a07654"
  }, 
  "json": {
    "price": 1.09223, 
    "sl": 1.09213, 
    "symbol": "EURUSD", 
    "tp": 1.09233, 
    "type": "BUY", 
    "volume": 0.01
  }, 
  "origin": "189.74.63.39", 
  "url": "https://httpbin.org/post"
}

「data」フィールドと「json」フィールドの中にオブジェクトが含まれていることにもう一度注目してください。これは、サーバーが本文で送信したデータを正しく受信したことを意味します。形式なしのプレーンテキストで本体を送信したい場合は、CHttpBodyクラスに文字列として挿入し、前回の記事で見たようにヘッダをtext/plainに変更するだけで済みます。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- URL
   CURL url;
   url.Parse("https://httpbin.org");
   url.Path("post");
   
   //--- Data to be sent
   string method = "POST";
   CHttpBody body;
   body.AddString("My simple text");
   
   //--- Body in char array
   char body_send[];
   body.GetAsBinary(body_send);
   
   //--- Headers that will be sent separated by "\n"
   CHttpHeader headers_send;
   headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)");
   headers_send.Add("Content-Type","text/plain");
   
   //--- Data that will be received
   char body_receive[];
   string headers_receive;
   
   //--- Send request
   int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive);
   
   //--- Show response
   Print("Respose: ",CharArrayToString(body_receive));
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+


結論

この記事では、HTTPリクエストにおける本体(ボディ)の概念を探り、そのクライアントとサーバー間のデータ伝送における基本的な役割を示しました。本体は送信するデータを配置する部分であり、JSON、XML、ファイルなどさまざまな形式でフォーマットできることを理解しましたが、特にAPIの文脈で最も一般的に使用されるJSONに焦点を当てて詳しく解説しました。また、リクエストをサーバーが正しく解釈するために、それぞれの本体フォーマットに必要なヘッダについても取り上げました。

さらに、Connexusライブラリで作成されたCHttpBodyクラスについても紹介しました。このクラスは、リクエストの本体を扱う作業を簡略化するためのもので、低レベルのフォーマット(バイト単位)を気にすることなく、データを容易に操作することが可能です。

次回の記事では、HTTPプロトコルの操作についてさらに深掘りし、GET、POST、PUT、DELETEといったメソッドについて解説します。また、Web上で最も有名な200 (Ok)、404 (Not Found)、500 (Internal Server Error)といったHTTPステータスコードと、それらがクライアントとサーバー間の通信においてどのような意味を持つかについても説明します。どうぞお楽しみに。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/16098

Controlsクラスを使用してインタラクティブなMQL5ダッシュボード/パネルを作成する方法(第1回):パネルの設定 Controlsクラスを使用してインタラクティブなMQL5ダッシュボード/パネルを作成する方法(第1回):パネルの設定
この記事では、取引操作を効率化するために設計されたMQL5のControlsクラスを使用して、インタラクティブな取引ダッシュボードを作成します。パネルには、タイトル、[Trade]、[Close]、[Information]のナビゲーションボタン、取引の実行とポジションの管理用の専用アクションボタンが表示されます。この記事を読み終える頃には、今後の記事でさらに機能強化するための基礎パネルが完成しているはずです。
データサイエンスとML(第31回):取引のためのCatBoost AIモデルの使用 データサイエンスとML(第31回):取引のためのCatBoost AIモデルの使用
CatBoost AIモデルは、その予測精度、効率性、散在する困難なデータセットに対する頑健性により、機械学習コミュニティの間で最近大きな人気を博しています。この記事では、外国為替市場を打ち負かすために、この種のモデルをどのように導入するかについて詳しく説明します。
スマートマネーコンセプト(オーダーブロック)とフィボナッチ指標を組み合わせた最適な取引エントリー方法 スマートマネーコンセプト(オーダーブロック)とフィボナッチ指標を組み合わせた最適な取引エントリー方法
SMC(オーダーブロック)は、機関投資家トレーダーが大規模なな売買を開始する主要領域です。価格が大きく動いた後、フィボナッチは直近のスイングハイからスイングローへの潜在的なリトレースメントを特定し、最適な取引エントリーを特定するのに役立ちます。
PythonとMQL5でロボットを開発する(第3回):モデルベース取引アルゴリズムの実装 PythonとMQL5でロボットを開発する(第3回):モデルベース取引アルゴリズムの実装
PythonとMQL5で自動売買ロボットを開発する連載を続けます。この記事では、Pythonで取引アルゴリズムを作成します。