English Русский 中文 Español Deutsch 日本語
preview
Assistente Connexus (Parte 5): Métodos HTTP e códigos de status

Assistente Connexus (Parte 5): Métodos HTTP e códigos de status

MetaTrader 5Exemplos |
17 0
joaopedrodev
joaopedrodev

Introdução

Este artigo é a continuação de uma série na qual estamos criando uma biblioteca chamada Connexus. No primeiro artigo entendemos os fundamentos da função WebRequest, exploramos cada um de seus parâmetros e criamos um exemplo de código que demonstra seu uso e as dificuldades envolvidas. No artigo anterior, compreendemos como funciona uma requisição, o que é o corpo da requisição e como enviar dados para o servidor e, no final, desenvolvemos o suporte a requisições com corpo.

Nesta quinta parte da série dedicada à criação da biblioteca Connexus, vamos abordar um aspecto importante do protocolo HTTP: métodos e códigos de status. Entender como cada operação HTTP funciona e como lidar com os códigos de status é fundamental para criar uma interação confiável entre clientes e servidores. Vamos nessa!


Métodos HTTP

Os métodos HTTP são as ações que solicitamos ao servidor para serem executadas. Ao enviar uma requisição HTTP, seja para acessar uma página ou enviar dados, você "conversa" com o servidor usando esses comandos. Aqui estão os principais:

  • GET: é o clássico "me dá isso". O navegador solicita acesso a algo no servidor, como uma página, uma imagem ou um arquivo. Ele apenas obtém a informação, sem alterar nada. É como pedir o cardápio em um restaurante apenas para ver o que eles oferecem.
  • POST: o POST é o entregador de encomendas. Aqui, você envia dados para o servidor. Isso é muito comum em formulários, por exemplo, ao se registrar em um site. Pense como se estivesse enviando uma carta: você aguarda que ela chegue ao destino e lá faça algo, como registrar você.
  • PUT: ao usar o comando PUT, você basicamente diz: "substitua isso aqui por esta nova versão". É usado para atualizar um recurso existente. É como trocar o óleo do carro – continua sendo o mesmo carro, mas agora com algo renovado.
  • DELETE: bem óbvio, né? Significa "remova isso daqui". Você pede para o servidor apagar algo. Adeus, não vamos mais nos encontrar.
  • PATCH: o PATCH é mais delicado. Ele altera apenas parte de um recurso. É como consertar uma peça quebrada de um brinquedo – não é necessário trocar tudo, apenas reparar o que está quebrado.
  • HEAD: é igual ao GET, mas sem o corpo. Você precisa apenas das informações do cabeçalho, não do conteúdo. É como ler o título de um livro sem abrir as páginas.

Existem também outros métodos, como CONNECT, OPTIONS e TRACE, mas eles raramente são usados no dia a dia de um desenvolvedor. Não vou detalhar cada um deles aqui, mas meu objetivo ao trabalhar com a biblioteca é que ela possa oferecer suporte a todos os métodos HTTP. Se você quiser saber mais sobre todos os métodos HTTP, consulte a documentação completa do protocolo aqui. Mas acredite, para a maioria dos problemas do dia a dia de um desenvolvedor, os métodos mais comuns, como GET, POST e DELETE, já são suficientes.

Quero destacar que usamos apenas um método para cada requisição, ou seja, uma requisição não pode ser do tipo GET e POST ao mesmo tempo.


Criação da classe CHttpMethod

Agora que entendemos cada método HTTP, sua finalidade e quando utilizá-lo, podemos partir para o código. Vamos implementar no Connexus uma classe responsável por armazenar o método HTTP que será utilizado na execução das requisições. Ela será bem simples e, independentemente do seu nível de programação, você entenderá a maior parte do que está acontecendo. Embora o objetivo da classe seja apenas guardar o método utilizado, como estamos trabalhando com uma classe, vamos adicionar funções extras para tornar o uso da biblioteca Connexus o mais simples possível para o usuário final.

Começamos criando uma nova pasta chamada Constants e, dentro dela, um novo arquivo chamado CHttpMethod, resultando no caminho: Include/Constants/HttpMethod.mqh. Dentro desse novo arquivo, vamos criar a classe CHttpMethod:

//+------------------------------------------------------------------+
//|                                                  HttpMethods.mqh |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| class : CHttpMethods                                             |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpMethods                                       |
//| Heritage    : No heritage                                        |
//| Description : Saved http method.                                 |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpMethod
  {
public:
                     CHttpMethod(void);
                    ~CHttpMethod(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpMethod::CHttpMethod(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CHttpMethod::~CHttpMethod(void)
  {
  }
//+------------------------------------------------------------------+

Para armazenar todos os possíveis métodos HTTP, vamos criar um enum que contenha todos os métodos possíveis de requisição HTTP. Também vamos adicionar à classe uma nova variável do tipo ENUM_HTTP_METHOD, chamada m_method:

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_HTTP_METHOD
  {
   HTTP_METHOD_NULL = 0,   // [0] Null
   HTTP_METHOD_CONNECT,    // [1] Connect
   HTTP_METHOD_DELETE,     // [2] Delete
   HTTP_METHOD_GET,        // [3] Get
   HTTP_METHOD_HEAD,       // [4] Head
   HTTP_METHOD_OPTION,     // [5] Option
   HTTP_METHOD_PATCH,      // [6] Patch
   HTTP_METHOD_POST,       // [7] Post
   HTTP_METHOD_PUT,        // [8] Put
   HTTP_METHOD_TRACE,      // [9] Trace
  };
//+------------------------------------------------------------------+
//| class : CHttpMethods                                             |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpMethods                                       |
//| Heritage    : No heritage                                        |
//| Description : Saved http method.                                 |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpMethod
  {
private:
   ENUM_HTTP_METHOD  m_method;                           // Stores the method that will be used
  };
//+------------------------------------------------------------------+

Agora que temos a variável que será usada para o armazenamento, vamos criar métodos auxiliares para definir e recuperar o método HTTP, em adição à sobrecarga do operador = para facilitar o uso das funções principais:

  • O operador de atribuição (operator= ): Permite definir diretamente o método HTTP usando o operador =.
  • SetMethod(ENUM_HTTP_METHOD) e SetMethod(string): Definimos o método HTTP usando um enum ou uma string. Se o parâmetro for do tipo string, ele utiliza a função StringToUpper() para formar corretamente a string.
  • GetMethod() e GetMethodDescription(): Obtêm o método HTTP e sua descrição em texto. 
  • void operator=(ENUM_HTTP_METHOD method): Essa é uma operação sobrecarregada, mas, em termos simples, ela é usada para definir o método HTTP usando o operador "=". Aqui vai um exemplo de como aplicar esse operador na prática:
    CHttpMethod method;
    method = HTTP_METHOD_POST;
  • Funções de verificação (IsPost(), IsGet() etc.): Elas facilitam a checagem do método, tornando o código mais legível e simples. Aqui está um exemplo de como essas funções podem nos ajudar:
    CHttpMethod method;
    method.SetMethod("POST")
    
    if(method.GetMethod() == HTTP_METHOD_POST)
      {
             //--- Action
      }
    //--- Or
    if(method.IsPost())
      {
             //--- Action
      }
    Assim, evitamos comparações explícitas de métodos.
A implementação desses métodos é a seguinte:
//+------------------------------------------------------------------+
//| class : CHttpMethod                                              |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpMethod                                        |
//| Heritage    : No heritage                                        |
//| Description : Saved http method.                                 |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpMethod
  {
private:

   ENUM_HTTP_METHOD  m_method;                           // Stores the method that will be used

public:
                     CHttpMethod(void);
                    ~CHttpMethod(void);
   //--- Get and set
   void              operator=(ENUM_HTTP_METHOD method);
   void              Set(ENUM_HTTP_METHOD method);
   bool              Set(string method);
   ENUM_HTTP_METHOD  Get(void);
   string            GetAsString(void);
   
   //--- Check method
   bool              IsConnect(void);
   bool              IsGet(void);
   bool              IsPost(void);
   bool              IsPut(void);
   bool              IsDelete(void);
   bool              IsPatch(void);
   bool              IsHead(void);
   bool              IsOption(void);
   bool              IsTrace(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpMethod::CHttpMethod(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CHttpMethod::~CHttpMethod(void)
  {
  }
//+------------------------------------------------------------------+
//|  Defines the http method                                         |
//+------------------------------------------------------------------+
void CHttpMethod::operator=(ENUM_HTTP_METHOD method)
  {
   m_method = method;
  }
//+------------------------------------------------------------------+
//|  Defines the http method                                         |
//+------------------------------------------------------------------+
void CHttpMethod::Set(ENUM_HTTP_METHOD method)
  {
   m_method = method;
  }
//+------------------------------------------------------------------+
//|  Defines the http method                                         |
//+------------------------------------------------------------------+
bool CHttpMethod::Set(string method)
  {
   string method_upper = method;
   StringToUpper(method_upper);
   if(method_upper == "CONNECT")
     {
      m_method = HTTP_METHOD_CONNECT;
      return(true);
     }
   else if(method_upper == "DELETE")
     {
      m_method = HTTP_METHOD_DELETE;
      return(true);
     }
   else if(method_upper == "GET")
     {
      m_method = HTTP_METHOD_GET;
      return(true);
     }
   else if(method_upper == "HEAD")
     {
      m_method = HTTP_METHOD_HEAD;
      return(true);
     }
   else if(method_upper == "OPTIONS")
     {
      m_method = HTTP_METHOD_OPTION;
      return(true);
     }
   else if(method_upper == "PATCH")
     {
      m_method = HTTP_METHOD_PATCH;
      return(true);
     }
   else if(method_upper == "POST")
     {
      m_method = HTTP_METHOD_POST;
      return(true);
     }
   else if(method_upper == "PUT")
     {
      m_method = HTTP_METHOD_PUT;
      return(true);
     }
   else if(method_upper == "TRACE")
     {
      m_method = HTTP_METHOD_TRACE;
      return(true);
     }
   return(false);
  }
//+------------------------------------------------------------------+
//| Get http method                                                  |
//+------------------------------------------------------------------+
ENUM_HTTP_METHOD CHttpMethod::Get(void)
  {
   return(m_method);
  }
//+------------------------------------------------------------------+
//| Get the description of the selected http method                  |
//+------------------------------------------------------------------+
string CHttpMethod::GetAsString(void)
  {
   switch(m_method)
     {
      case HTTP_METHOD_NULL:
         return "NULL";
      case HTTP_METHOD_CONNECT:
         return "CONNECT";
      case HTTP_METHOD_DELETE:
         return "DELETE";
      case HTTP_METHOD_GET:
         return "GET";
      case HTTP_METHOD_HEAD:
         return "HEAD";
      case HTTP_METHOD_OPTION:
         return "OPTIONS";
      case HTTP_METHOD_PATCH:
         return "PATCH";
      case HTTP_METHOD_POST:
         return "POST";
      case HTTP_METHOD_PUT:
         return "PUT";
      case HTTP_METHOD_TRACE:
         return "TRACE";

      default:
         return "Unknown HTTP Method";
     }
  }
//+------------------------------------------------------------------+
//| Check if method is connect                                       |
//+------------------------------------------------------------------+
bool CHttpMethod::IsConnect(void)
  {
   return(m_method == HTTP_METHOD_CONNECT);
  }
//+------------------------------------------------------------------+
//| Check if method is get                                           |
//+------------------------------------------------------------------+
bool CHttpMethod::IsGet(void)
  {
   return(m_method == HTTP_METHOD_GET);
  }
//+------------------------------------------------------------------+
//| Check if method is post                                          |
//+------------------------------------------------------------------+
bool CHttpMethod::IsPost(void)
  {
   return(m_method == HTTP_METHOD_POST);
  }
//+------------------------------------------------------------------+
//| Check if method is put                                           |
//+------------------------------------------------------------------+
bool CHttpMethod::IsPut(void)
  {
   return(m_method == HTTP_METHOD_PUT);
  }
//+------------------------------------------------------------------+
//| Check if method is delete                                        |
//+------------------------------------------------------------------+
bool CHttpMethod::IsDelete(void)
  {
   return(m_method == HTTP_METHOD_DELETE);
  }
//+------------------------------------------------------------------+
//| Check if method is patch                                         |
//+------------------------------------------------------------------+
bool CHttpMethod::IsPatch(void)
  {
   return(m_method == HTTP_METHOD_PATCH);
  }
//+------------------------------------------------------------------+
//| Check if method is head                                          |
//+------------------------------------------------------------------+
bool CHttpMethod::IsHead(void)
  {
   return(m_method == HTTP_METHOD_HEAD);
  }
//+------------------------------------------------------------------+
//| Check if method is option                                        |
//+------------------------------------------------------------------+
bool CHttpMethod::IsOption(void)
  {
   return(m_method == HTTP_METHOD_OPTION);
  }
//+------------------------------------------------------------------+
//| Check if method is trace                                         |
//+------------------------------------------------------------------+
bool CHttpMethod::IsTrace(void)
  {
   return(m_method == HTTP_METHOD_TRACE);
  }
//+------------------------------------------------------------------+

Com isso, finalizamos a classe responsável por armazenar o método HTTP utilizado. Agora contamos com algumas funções auxiliares que vão poupar código no futuro. Vamos para a próxima classe de suporte.


Código de status

Os códigos de status, em termos simples, são números. Esse número é padronizado e enviado pelo servidor ao cliente após o processamento da requisição. Cada código é formado por três dígitos, sendo que o primeiro indica a categoria à qual o status pertence (1xx, 2xx, 3xx, 4xx e 5xx). Esse código apenas informa o resultado da requisição: se foi bem-sucedida, se houve erro do lado do servidor ou se a requisição foi feita de forma incorreta. Existem diversos códigos de status. Isso vai de 100 a 599, divididos em 5 categorias. Para saber a qual categoria um código pertence, basta identificar em qual faixa ele está, veja a tabela com os valores:

Faixa do código de status Descrição
100-199
Não é algo que vemos com frequência. São respostas do tipo "estou processando, aguarde". É o servidor informando que está trabalhando na sua requisição, mas ainda não terminou.
200-299
Ah, essa é a resposta que mais gostamos! Significa que tudo ocorreu bem. O mais famoso deles é o 200 OK – sinal de que "deu tudo certo". Você pediu, foi entregue. Simples assim.
300-399
Aqui, o servidor basicamente diz: "Ops, você está no lugar errado, vá para lá". O 301 "Movido permanentemente" é um redirecionamento definitivo, enquanto o 302 "Encontrado" é temporário, algo como: "Estou em manutenção, mas você pode achar isso aqui por enquanto".
400-499
São os famosos erros que nós, usuários, frequentemente cometemos. O mais conhecido é o 404 "Não encontrado", quando a página que você procura simplesmente não existe. É como chegar no endereço certo e descobrir que o prédio foi demolido.
500-599
Agora, quando o problema está do outro lado, a culpa é do servidor. O famoso erro interno do servidor 500 é, basicamente, quando o servidor levanta as mãos e diz: "alguma coisa deu errado por aqui".

Existem vários códigos possíveis. Não vou descrever todos para não deixar o artigo longo demais. Se quiser conhecer todos os valores possíveis, leia aqui, onde cada código é explicado em detalhes. Se quiser saber mais sobre o protocolo HTTP, vale a pena essa leitura. No dia a dia de um desenvolvedor, usamos apenas alguns códigos, e muitos deles raramente são vistos na internet. Aqui estão os mais comuns:

1xx: Informativo

  • 100 Continue: O servidor recebeu os cabeçalhos e o cliente pode continuar enviando o corpo da requisição.
  • 101 Switching Protocols: O cliente solicitou a troca de protocolo e o servidor aceitou.

2xx: Sucesso

  • 200 OK: A requisição foi concluída com sucesso.
  • 201 Created: A requisição foi concluída com sucesso e um novo recurso foi criado. 204 No Content: A requisição foi concluída com sucesso, mas a resposta não contém conteúdo.

3xx: Redirecionamento

  • 301 Moved Permanently: O recurso foi movido permanentemente para um novo URL.
  • 302 Found: O recurso foi movido temporariamente para um novo URL.
  • 304 Not Modified: O recurso não foi modificado desde a última requisição, permitindo ao cliente usar a versão em cache.

4xx: Erros do cliente

  • 400 Bad Request: A requisição é inválida ou foi malformada.
  • 401 Unauthorized: Acesso não autorizado; é necessária autenticação.
  • 403 Forbidden: O servidor entendeu a requisição, mas negou o acesso.
  • 404 Not Found: O recurso solicitado não foi encontrado.
  • 405 Method Not Allowed: O método HTTP usado não é permitido para o recurso solicitado.

5xx: Erros do servidor

  • 500 Internal Server Error: Ocorreu um erro genérico no servidor.
  • 502 Bad Gateway: O servidor recebeu uma resposta inválida ao tentar processar a requisição.
  • 503 Service Unavailable: O servidor está temporariamente indisponível, geralmente por sobrecarga ou manutenção.
  • 504 Gateway Timeout: O servidor não recebeu resposta a tempo de outro servidor ao qual tentou se conectar.

Agora que entendemos todas as categorias de status e os mais utilizados, quero que a biblioteca seja capaz de lidar com todos os status possíveis. Para isso, vamos criar uma classe capaz de processar qualquer código de status recebido do servidor, desde que ele seja válido.


Criação da classe CHttpStatusCode

Agora que conhecemos todos os possíveis códigos de status, vamos adicionar a implementação correspondente na biblioteca. O objetivo aqui é simples: criar uma classe responsável por armazenar o código de status recebido. Essa classe também deve oferecer suporte para a descrição de cada status, além de permitir identificar rapidamente a qual categoria esse status pertence.

Vamos ao código. Na mesma pasta criada anteriormente para a classe CHttpMethod, vamos criar um novo arquivo chamado HttpStatusCode.mqh. No final, o caminho completo ficará assim: Includes/Connexus/Constants/HttpStatusCode.mqh.

//+------------------------------------------------------------------+
//|                                               HttpStatusCode.mqh |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| class : CHttpStatusCodes                                         |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpStatusCodes                                   |
//| Heritage    : No heritage                                        |
//| Description : Saved http status code.                            |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpStatusCodes
  {
public:
                     CHttpStatusCodes(void);
                    ~CHttpStatusCodes(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpStatusCodes::CHttpStatusCodes(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CHttpStatusCodes::~CHttpStatusCodes(void)
  {
  }
//+------------------------------------------------------------------+

Para conter todos os possíveis códigos de status, vamos criar um enum com todos os valores possíveis. O nome do enum será ENUM_HTTP_STATUS, e cada valor corresponderá ao código de status adequado.

enum ENUM_HTTP_STATUS
  {
//--- Mql error
   HTTP_STATUS_URL_NOT_ALLOWED = -1,
   HTTP_STATUS_URL_NOT_DEFINED = 1,
   HTTP_STATUS_METHOD_NOT_DEFINED = 2,

//--- Informational
   HTTP_STATUS_CONTINUE = 100,
   HTTP_STATUS_SWITCHING_PROTOCOLS = 101,
   HTTP_STATUS_PROCESSING = 102,
   HTTP_STATUS_EARLY_HINTS = 103,

//--- Successul
   HTTP_STATUS_OK = 200,
   HTTP_STATUS_CREATED = 201,
   HTTP_STATUS_ACCEPTED = 202,
   HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
   HTTP_STATUS_NO_CONTENT = 204,
   HTTP_STATUS_RESET_CONTENT = 205,
   HTTP_STATUS_PARTIAL_CONTENT = 206,
   HTTP_STATUS_MULTI_STATUS = 207,
   HTTP_STATUS_ALREADY_REPORTED = 208,

//--- Redirection messages
   HTTP_STATUS_MULTIPLE_CHOICES = 300,
   HTTP_STATUS_MOVED_PERMANENTLY = 301,
   HTTP_STATUS_FOUND = 302,
   HTTP_STATUS_SEE_OTHER = 303,
   HTTP_STATUS_NOT_MODIFIED = 304,
   HTTP_STATUS_USE_PROXY = 305,
   HTTP_STATUS_SWITCH_PROXY = 306,
   HTTP_STATUS_TEMPORARY_REDIRECT = 307,
   HTTP_STATUS_PERMANENT_REDIRECT = 308,

//--- Client error
   HTTP_STATUS_BAD_REQUEST = 400,
   HTTP_STATUS_UNAUTHORIZED = 401,
   HTTP_STATUS_PAYMENT_REQUIRED = 402,
   HTTP_STATUS_FORBIDDEN = 403,
   HTTP_STATUS_NOT_FOUND = 404,
   HTTP_STATUS_METHOD_NOT_ALLOWED = 405,
   HTTP_STATUS_NOT_ACCEPTABLE = 406,
   HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
   HTTP_STATUS_REQUEST_TIMEOUT = 408,
   HTTP_STATUS_CONFLICT = 409,
   HTTP_STATUS_GONE = 410,
   HTTP_STATUS_LENGTH_REQUIRED = 411,
   HTTP_STATUS_PRECONDITION_FAILED = 412,
   HTTP_STATUS_PAYLOAD_TOO_LARGE = 413,
   HTTP_STATUS_URI_TOO_LONG = 414,
   HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
   HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416,
   HTTP_STATUS_EXPECTATION_FAILED = 417,
   HTTP_STATUS_MISDIRECTED_REQUEST = 421,
   HTTP_STATUS_UNPROCESSABLE_ENTITY = 422,
   HTTP_STATUS_LOCKED = 423,
   HTTP_STATUS_FAILED_DEPENDENCY = 424,
   HTTP_STATUS_TOO_EARLY = 425,
   HTTP_STATUS_UPGRADE_REQUIRED = 426,
   HTTP_STATUS_PRECONDITION_REQUIRED = 428,
   HTTP_STATUS_TOO_MANY_REQUESTS = 429,
   HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
   HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451,

//--- Server error
   HTTP_STATUS_INTERNAL_SERVER_ERROR = 500,
   HTTP_STATUS_NOT_IMPLEMENTED = 501,
   HTTP_STATUS_BAD_GATEWAY = 502,
   HTTP_STATUS_SERVICE_UNAVAILABLE = 503,
   HTTP_STATUS_GATEWAY_TIMEOUT = 504,
   HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505,
   HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506,
   HTTP_STATUS_INSUFFICIENT_STORAGE = 507,
   HTTP_STATUS_LOOP_DETECTED = 508,
   HTTP_STATUS_NOT_EXTENDED = 510,
   HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511
  };

Observe que adicionei alguns comentários separando as categorias de cada status. Note também que nos primeiros valores do enum incluí "códigos de status personalizados", que serão gerados automaticamente pela biblioteca, são eles:

  • HTTP_STATUS_URL_NOT_ALLOWED: O URL não foi adicionado à lista de URLs permitidos no terminal
  • HTTP_STATUS_URL_NOT_DEFINED: O URL não foi definido na requisição
  • HTTP_STATUS_METHOD_NOT_DEFINED: Não foi definido um método válido para a requisição

Quando a função WebRequest é chamada e retorna o valor -1, isso significa que o URL não foi adicionado no terminal, conforme indicado na documentação do MQL5, portanto a biblioteca deve automaticamente retornar HTTP_STATUS_URL_NOT_ALLOWED. A mesma lógica será aplicada para os outros códigos personalizados, mas não vamos nos aprofundar nisso agora.

Seguindo com o desenvolvimento da classe, ela será semelhante à CHttpMethod, vamos adicionar uma nova variável privada chamada m_status do tipo ENUM_HTTP_STATUS, além de alguns métodos auxiliares para definir e obter o valor dessa variável:

  • operator=(int) e operator=(ENUM_HTTP_STATUS): Definem o valor de m_status usando o operador =, recebendo um número inteiro ou um valor enumerado.
  • Set(ENUM_HTTP_STATUS): Define o código de status usando um valor do enum.
  • Get() e GetMessage(): Retornam o código de status atual ou apenas a mensagem correspondente ao código armazenado.

Abaixo está o código com a implementação desses métodos:

//+------------------------------------------------------------------+
//| class : CHttpStatusCodes                                         |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpStatusCodes                                   |
//| Heritage    : No heritage                                        |
//| Description : Saved http status code.                            |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpStatusCodes
  {
private:
   
   ENUM_HTTP_STATUS  m_status;                           // Stores the status used
   
public:
                     CHttpStatusCodes(void);
                    ~CHttpStatusCodes(void);

   //--- Set
   void              operator=(int status);
   void              operator=(ENUM_HTTP_STATUS status);
   void              Set(ENUM_HTTP_STATUS status);
   
   //--- Get
   ENUM_HTTP_STATUS  Get(void);
   string            GetMessage(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpStatusCodes::CHttpStatusCodes(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CHttpStatusCodes::~CHttpStatusCodes(void)
  {
  }

//+------------------------------------------------------------------+
//| Assignment operator to set status from integer value             |
//+------------------------------------------------------------------+ 
void CHttpStatusCodes::operator=(int status)
  {
   m_status = (ENUM_HTTP_STATUS)status;
  }

//+------------------------------------------------------------------+
//| Assignment operator to set status from ENUM_HTTP_STATUS          |
//+------------------------------------------------------------------+ 
void CHttpStatusCodes::operator=(ENUM_HTTP_STATUS status)
  {
   m_status = status;
  }

//+------------------------------------------------------------------+
//| Sets the HTTP status code                                        |
//+------------------------------------------------------------------+ 
void CHttpStatusCodes::Set(ENUM_HTTP_STATUS status)
  {
   m_status = status;
  }

//+------------------------------------------------------------------+
//| Returns the stored HTTP status code                              |
//+------------------------------------------------------------------+ 
ENUM_HTTP_STATUS CHttpStatusCodes::Get(void)
  {
   return(m_status);
  }

//+------------------------------------------------------------------+
//| Returns a message corresponding to the stored HTTP status code   |
//+------------------------------------------------------------------+ 
string CHttpStatusCodes::GetMessage(void)
  {
   switch(m_status)
     {
      case HTTP_STATUS_URL_NOT_ALLOWED:
         return "The URL was not added to the list of allowed URLs in the terminal";
      case HTTP_STATUS_URL_NOT_DEFINED:
         return "URL was not defined in the request";
      case HTTP_STATUS_METHOD_NOT_DEFINED:
         return "Method was not defined in the request";
      
      case HTTP_STATUS_CONTINUE:
         return "Continue";
      case HTTP_STATUS_SWITCHING_PROTOCOLS:
         return "Switching Protocols";
      case HTTP_STATUS_PROCESSING:
         return "Processing";
      case HTTP_STATUS_EARLY_HINTS:
         return "Early Hints";

      case HTTP_STATUS_OK:
         return "OK";
      case HTTP_STATUS_CREATED:
         return "Created";
      case HTTP_STATUS_ACCEPTED:
         return "Accepted";
      case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION:
         return "Non-Authoritative Information";
      case HTTP_STATUS_NO_CONTENT:
         return "No Content";
      case HTTP_STATUS_RESET_CONTENT:
         return "Reset Content";
      case HTTP_STATUS_PARTIAL_CONTENT:
         return "Partial Content";
      case HTTP_STATUS_MULTI_STATUS:
         return "Multi-Status";
      case HTTP_STATUS_ALREADY_REPORTED:
         return "Already Reported";

      case HTTP_STATUS_MULTIPLE_CHOICES:
         return "Multiple Choices";
      case HTTP_STATUS_MOVED_PERMANENTLY:
         return "Moved Permanently";
      case HTTP_STATUS_FOUND:
         return "Found";
      case HTTP_STATUS_SEE_OTHER:
         return "See Other";
      case HTTP_STATUS_NOT_MODIFIED:
         return "Not Modified";
      case HTTP_STATUS_USE_PROXY:
         return "Use Proxy";
      case HTTP_STATUS_SWITCH_PROXY:
         return "Switch Proxy";
      case HTTP_STATUS_TEMPORARY_REDIRECT:
         return "Temporary Redirect";
      case HTTP_STATUS_PERMANENT_REDIRECT:
         return "Permanent Redirect";

      case HTTP_STATUS_BAD_REQUEST:
         return "Bad Request";
      case HTTP_STATUS_UNAUTHORIZED:
         return "Unauthorized";
      case HTTP_STATUS_PAYMENT_REQUIRED:
         return "Payment Required";
      case HTTP_STATUS_FORBIDDEN:
         return "Forbidden";
      case HTTP_STATUS_NOT_FOUND:
         return "Not Found";
      case HTTP_STATUS_METHOD_NOT_ALLOWED:
         return "Method Not Allowed";
      case HTTP_STATUS_NOT_ACCEPTABLE:
         return "Not Acceptable";
      case HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
         return "Proxy Authentication Required";
      case HTTP_STATUS_REQUEST_TIMEOUT:
         return "Request Timeout";
      case HTTP_STATUS_CONFLICT:
         return "Conflict";
      case HTTP_STATUS_GONE:
         return "Gone";
      case HTTP_STATUS_LENGTH_REQUIRED:
         return "Length Required";
      case HTTP_STATUS_PRECONDITION_FAILED:
         return "Precondition Failed";
      case HTTP_STATUS_PAYLOAD_TOO_LARGE:
         return "Payload Too Large";
      case HTTP_STATUS_URI_TOO_LONG:
         return "URI Too Long";
      case HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE:
         return "Unsupported Media Type";
      case HTTP_STATUS_RANGE_NOT_SATISFIABLE:
         return "Range Not Satisfiable";
      case HTTP_STATUS_EXPECTATION_FAILED:
         return "Expectation Failed";
      case HTTP_STATUS_MISDIRECTED_REQUEST:
         return "Misdirected Request";
      case HTTP_STATUS_UNPROCESSABLE_ENTITY:
         return "Unprocessable Entity";
      case HTTP_STATUS_LOCKED:
         return "Locked";
      case HTTP_STATUS_FAILED_DEPENDENCY:
         return "Failed Dependency";
      case HTTP_STATUS_TOO_EARLY:
         return "Too Early";
      case HTTP_STATUS_UPGRADE_REQUIRED:
         return "Upgrade Required";
      case HTTP_STATUS_PRECONDITION_REQUIRED:
         return "Precondition Required";
      case HTTP_STATUS_TOO_MANY_REQUESTS:
         return "Too Many Requests";
      case HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE:
         return "Request Header Fields Too Large";
      case HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS:
         return "Unavailable For Legal Reasons";

      case HTTP_STATUS_INTERNAL_SERVER_ERROR:
         return "Internal Server Error";
      case HTTP_STATUS_NOT_IMPLEMENTED:
         return "Not Implemented";
      case HTTP_STATUS_BAD_GATEWAY:
         return "Bad Gateway";
      case HTTP_STATUS_SERVICE_UNAVAILABLE:
         return "Service Unavailable";
      case HTTP_STATUS_GATEWAY_TIMEOUT:
         return "Gateway Timeout";
      case HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED:
         return "HTTP Version Not Supported";
      case HTTP_STATUS_VARIANT_ALSO_NEGOTIATES:
         return "Variant Also Negotiates";
      case HTTP_STATUS_INSUFFICIENT_STORAGE:
         return "Insufficient Storage";
      case HTTP_STATUS_LOOP_DETECTED:
         return "Loop Detected";
      case HTTP_STATUS_NOT_EXTENDED:
         return "Not Extended";
      case HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED:
         return "Network Authentication Required";
      default:
         return "Unknown HTTP Status";
     }
  }
//+------------------------------------------------------------------+

Vamos adicionar também alguns métodos auxiliares responsáveis por verificar se o código de status armazenado na classe pertence a uma determinada categoria, são eles:

  • bool IsInformational(void): Faixa informativa (100 - 199)
  • bool IsSuccess(void): Faixa de sucesso (200 - 299)
  • bool IsRedirection(void): Faixa de redirecionamento (300 - 399)
  • bool IsClientError(void): Faixa de erro do cliente (400 - 499)
  • bool IsServerError(void): Faixa de erro do servidor (500 - 599)
//+------------------------------------------------------------------+
//| class : CHttpStatusCodes                                         |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpStatusCodes                                   |
//| Heritage    : No heritage                                        |
//| Description : Saved http status code.                            |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpStatusCodes
  {
private:
   
   ENUM_HTTP_STATUS  m_status;                           // Stores the status used
   
public:
                     CHttpStatusCodes(void);
                    ~CHttpStatusCodes(void);
   
   //--- Check which group the code is in
   bool              IsInformational(void);              // Checks if the status code is in the informational response range (100 - 199)
   bool              IsSuccess(void);                    // Check if the status code is in the success range (200 - 299)
   bool              IsRedirection(void);                // Check if the status code is in the redirect range (300 - 399)
   bool              IsClientError(void);                // Checks if the status code is in the client error range (400 - 499)
   bool              IsServerError(void);                // Check if the status code is in the server error range (500 - 599)
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpStatusCodes::CHttpStatusCodes(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CHttpStatusCodes::~CHttpStatusCodes(void)
  {
  }
//+------------------------------------------------------------------+
//| Checks if the status code is in the informational response       |
//| range (100 - 199)                                                |
//+------------------------------------------------------------------+
bool CHttpStatusCodes::IsInformational(void)
  {
   return(m_status >= 100 && m_status <= 199);
  }
//+------------------------------------------------------------------+
//| Check if the status code is in the success range (200 - 299)     |
//+------------------------------------------------------------------+
bool CHttpStatusCodes::IsSuccess(void)
  {
   return(m_status >= 200 && m_status <= 299);
  }
//+------------------------------------------------------------------+
//| Check if the status code is in the redirect range (300 - 399)    |
//+------------------------------------------------------------------+
bool CHttpStatusCodes::IsRedirection(void)
  {
   return(m_status >= 300 && m_status <= 399);
  }
//+------------------------------------------------------------------+
//| Checks if the status code is in the client error range           |
//| (400 - 499)                                                      |
//+------------------------------------------------------------------+
bool CHttpStatusCodes::IsClientError(void)
  {
   return(m_status >= 400 && m_status <= 499);
  }
//+------------------------------------------------------------------+
//| Check if the status code is in the server error range (500 - 599)|
//+------------------------------------------------------------------+
bool CHttpStatusCodes::IsServerError(void)
  {
   return(m_status >= 500 && m_status <= 599);
  }
//+------------------------------------------------------------------+


Conclusão

Para tornar o funcionamento da biblioteca mais claro, siga o esquema abaixo:

Diagram

Já temos prontos todos os classes auxiliares responsáveis pelo tratamento independente de cada elemento HTTP. Temos as classes CQueryParam, CHttpHeader e CHttpBody, que utilizam a classe CJson, mas sem relação de herança entre elas. As classes criadas neste artigo ainda não estão conectadas às demais; na próxima parte, vamos integrá-las, criando a requisição e a resposta HTTP.

Neste artigo, tratamos dos métodos HTTP e dos códigos de status, dois elementos fundamentais na comunicação entre cliente e servidor na internet. Compreender o que cada método faz de fato permite criar requisições mais precisas, informando ao servidor qual ação deve ser executada e tornando a comunicação mais eficiente. Cada método tem um papel específico na comunicação, e usá-lo corretamente torna a interação com APIs mais clara, tanto para o cliente quanto para o servidor, evitando surpresas.

Além disso, falamos sobre os códigos de status, que são a resposta direta do servidor sobre o que aconteceu com a requisição. Eles variam desde o simples "tudo certo" (200 OK) até mensagens de erro no lado do cliente (4xx) ou no lado do servidor (5xx). Saber lidar com esses códigos é uma habilidade valiosa, já que muitas vezes um erro não significa o fim do processo, mas sim a oportunidade de ajustar ou tentar novamente.

Durante o desenvolvimento da biblioteca Connexus, aprendemos como lidar com cada um desses elementos, o que deixa a biblioteca mais robusta e preparada para lidar com as particularidades da comunicação HTTP. A partir de agora, nossa classe responsável por métodos e códigos de status estará pronta para oferecer ao desenvolvedor mais controle e segurança ao interagir com APIs.

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/16136

Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
Criando um EA em MQL5 com base na estratégia de Rompimento do Intervalo Diário (Daily Range Breakout) Criando um EA em MQL5 com base na estratégia de Rompimento do Intervalo Diário (Daily Range Breakout)
Neste artigo, criamos um EA em MQL5 com base na estratégia de Rompimento do Intervalo Diário (Daily Range Breakout). Vamos abordar os conceitos-chave da estratégia, desenvolver o esquema do EA e implementar a lógica de rompimento em MQL5. Por fim, estudamos os métodos de backtest e otimização do EA para maximizar sua eficiência.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Reimaginando Estratégias Clássicas (Parte IX): Análise de Múltiplos Time-Frames (II) Reimaginando Estratégias Clássicas (Parte IX): Análise de Múltiplos Time-Frames (II)
Na discussão de hoje, examinamos a estratégia de análise de múltiplos time-frames para descobrir em qual time-frame nosso modelo de IA apresenta melhor desempenho. Nossa análise nos levou a concluir que os time-frames Mensal e de 1 Hora produzem modelos com taxas de erro relativamente baixas no par EURUSD. Usamos isso a nosso favor e criamos um algoritmo de negociação que faz previsões de IA no time-frame Mensal e executa suas negociações no time-frame de 1 Hora.