HTTP Access

Elements RTL provides the static Http class and a suite of helper types around it, in order to facilitate making network requests using the HTTP (and HTTPS) protocols in a cross-=platform fashion.

Under the hood, Http uses then networking infrastructure provided by each platform, meaning its a reliable and well-tested system fior making HTTP requests that is used by many developers and users every day, and subject to the continued improvements and security maintenance doe by the platform vendors. It wraps this infrastructure in a common API that can be use din the same way, on all platforms.

Http does not (currently) provide all the bells for controlling every detail of the HTTP stack – you can fall back to the platform-specific APIs for that, if necessary – but it provides access to the most commonly needed functionality, incuding the ability to make GET and POST requests, access headers, and controll redirect handling.

By default, Http is designed to be used asynchronously, meaning requests run in the background and will trigger callbacks as necessary. That is recommended practise on all platforms, and even mandatory on some (such as Windows Phone). Synchronous APIs are provided for use in server or command-line applications, but should be used sparingly.

ExecuteRequest()

The core API method on the Http class is ExecuteRequest(), which takes either an URL or a more well-configured HttpRequest class instance, and initiates a request to that address. A callback block is provided thaty will be executed, once the request has been completed and a response (but not necessarily all the response data) has been received from the server.

Http.ExecuteRequest(new Url('http://www.elementscompiler.com'), response -> begin
  // handle the response
end);
Http.ExecuteRequest(new Url("http://www.elementscompiler.com"), (response) => {
  // handle the response
});
Http.ExecuteRequest(Url("http://www.elementscompiler.com") { response in
  // handle the response
});
Http.ExecuteRequest(new Url("http://www.elementscompiler.com"), (response) => {
  // handle the response
});

By default when just passing a Url, ExecuteRequest will perform a GET request without content. You can also manually consttruct a HttpRequest object and configure it in more detail, for example to make a POST request, or send custom headers or a body with your request. We'll look at that in more detail later.

Once a response comes from the server, the provided callback block will be called, passing in a HttpResponse object.

HttpResponse

HttpResponse has a few properties and methods worth noting. First, the Success property allows you to check whether the request succeeded or failed. If it failed (which could be due to network errors, a bad URL, or an error response from the server, you can check the Exception property for details on the failure.

You can also manually check the HTTP response code via the Code property, and inspect any Headers the server returned.

Of course, the most interesting part of an HTTP request will be the returned data, the body of the response. Because the data returned by request can be large and/or slow to come in, that data is not immediately available as part of the response. In fact, data might still be coming in slowly but steadily over the network, as your response callback is already executing.

HttpResponse has a few helper methods that let you get access to the response content, asynchronously. Just as with the initial request, you will call (one of) these methods, and pass a block that will be called back once the data bas been received. Currently, four methods are provided that will return the data in different formats, depending on our needs. Over time, additionaklm formats may be added. These methods are:

method GetContentAsString(aEncoding: Encoding := nil; contentCallback: HttpContentResponseBlock<String>);
method GetContentAsBinary(contentCallback: HttpContentResponseBlock<Binary>);
method GetContentAsXml(contentCallback: HttpContentResponseBlock<XmlDocument>);
method GetContentAsJson(contentCallback: HttpContentResponseBlock<JsonDocument>);
void GetContentAsString(Encoding aEncoding = null, HttpContentResponseBlock<String> contentCallback);
void GetContentAsBinary(HttpContentResponseBlock<Binary> contentCallback);
void GetContentAsXml(HttpContentResponseBlock<XmlDocument> contentCallback);
void GetContentAsJson(HttpContentResponseBlock<JsonDocument> contentCallback);
func GetContentAsString(_ wncoding: Encoding? = nil; _ contentCallback: HttpContentResponseBlock<String>)
func GetContentAsBinary(_ contentCallback: HttpContentResponseBlock<Binary>)
func GetContentAsXml(_ contentCallback: HttpContentResponseBlock<XmlDocument>)
func GetContentAsJson(_ contentCallback: HttpContentResponseBlock<JsonDocument>)
void GetContentAsString(Encoding aEncoding = null, HttpContentResponseBlock<String> contentCallback);
void GetContentAsBinary(HttpContentResponseBlock<Binary> contentCallback);
void GetContentAsXml(HttpContentResponseBlock<XmlDocument> contentCallback);
void GetContentAsJson(HttpContentResponseBlock<JsonDocument> contentCallback);

You will note that, aside from the optional Encoding parameter for GetContentAsString, all four versions look identical, expept for the generic parameter to the callback block.

Calling any of these methods, the Http class will go out in the background, retrieve the full data for the request and – here necessary decode it to a String, Json or Xml object. Once done, the provided callback block will be called.

HttpResponseContent<T>

Just like the response, the passed HttpResponseContent object will have a Success property that indicates if everything went well (for example, the data might not be valid XML, or the data might not be convertable as a string with the given encoding). If everything worked, the Content property – generically typed to be the right kind of data you would expect – gives you access to the received content.

Http.ExecuteRequest(new Url('http://www.elementscompiler.com'), response -> begin
  if response.Success then begin
    response.GetContentAsString(nil, content -> begin
      if content.Success then
        writeLn('Response was: '+content.Content);
    end);
  end;
end);
Http.ExecuteRequest(new Url("http://www.elementscompiler.com"), (response) => {
  if (response.Success)
  {
    response.GetContentAsString(null, (content) => {
      if (content.Success)
        writeLn("Response was: "+content.Content);
    });
  end;
});
Http.ExecuteRequest(Url("http://www.elementscompiler.com") { response in
  if response.Success {
    response.GetContentAsString(nil) { content in
      if content.Success {
        writeLn("Response was: "+content.Content);
      }
    });
  };
});
Http.ExecuteRequest(new Url("http://www.elementscompiler.com"), (response) => {
  if (response.Success)
  {
    response.GetContentAsString(null, (content) => {
      if (content.Success)
        writeLn("Response was: "+content.Content);
    });
  end;
});

To do: to be concluded