Archicad 30 C++ API
Loading...
Searching...
No Matches
HTTPClient module

HTTPClient is a module for sending HTTP requests to and receiving responses from a URL. It uses the curl library under the hood, but this is an implementation detail not exposed to the users of the module.

It supports the following features:

  • Sending requests with
    • various methods (GET, POST, PUT, HEAD, etc.)
    • custom headers
    • custom content with content types
    • multipart form data
  • Asynchronous request execution
  • Sending and receiving IO::Files
  • Redirect handling
  • Timeouts
  • Built-in logging

Testing and debugging considerations

The module by default validates certificates used by HTTPS utilizing the OS’s certificate store.

This might be problematic if an HTTP mock server is used by tests.

This check can be bypassed by setting the following environment variable: GS_HTTP_CLIENT_SSL_CERTIFICATE_VERIFICATION_DISABLED

Examples

A simple HEAD request

HTTPClient::PendingResult pendingResult = HTTPClient::Head (IO::URI::URI ("https://graphisoft.com"));
pendingResult.Wait ();
auto result = pendingResult.AcquireResult ();
if (result.IsValue () && result->GetStatusCode () == HTTPClient::StandardStatusCode::OK)
std::cout << "GS website seems reachable and functioning" << std::endl;

A simple GET request

HTTPClient::PendingResult pendingResult = HTTPClient::Get (IO::URI::URI ("https://httpbin.org/uuid"));
pendingResult.Wait ();
auto result = pendingResult.AcquireResult ();
if (result.IsValue () && result->GetStatusCode () == HTTPClient::StandardStatusCode::OK) {
rapidjson::Document document;
document.Parse (result->GetContent ()->ReadAsUniString ().ToCStr ());
std::cout << "Received UUID: " << document["uuid"].GetString () << std::endl;
} else {
std::cout << "Unexpected result!" << std::endl;
}

Adding request headers

HTTPClient::Headers headers = { { HTTPClient::StandardHeaderFields::Authorization, "Bearer 123" } };
HTTPClient::PendingResult pendingResult = HTTPClient::Get (IO::URI::URI ("https://httpbin.org/bearer"), headers);
pendingResult.Wait ();
auto result = pendingResult.AcquireResult ();
if (result.IsValue () && result->GetStatusCode () == HTTPClient::StandardStatusCode::OK)
std::cout << "Successful authentication!" << std::endl;
else
std::cout << "Authentication failed! " << std::endl;

Asynchronous operation

HTTPClient::PendingResult pendingResult = HTTPClient::Get (IO::URI::URI ("https://httpbin.org/delay/5"));
std::cout << "Waiting for request to complete";
do {
pendingResult.Wait (100, false);
std::cout << "." << std::flush;
} while (!pendingResult.IsCompleted ());
std::cout << std::endl;
auto result = pendingResult.AcquireResult ();
if (result.IsValue () && result->GetStatusCode () == HTTPClient::StandardStatusCode::OK)
std::cout << "Request completed successfully!" << std::endl;
else
std::cout << "Unexpected result!" << std::endl;

Response content downloaded to a file

IO::Location fileLocation;
IO::fileSystem.GetSpecialLocation (IO::FileSystem::TemporaryFolder, &fileLocation);
fileLocation.AppendToLocal (IO::Name ("result" + GS::Guid (GS::Guid::GenerateGuidSelector::GenerateGuid).ToUniString () + ".jpg"));
HTTPClient::OutputFile filePtr = new IO::File (fileLocation, IO::File::OnNotFound::Create);
filePtr->Open (IO::File::OpenMode::ReadWriteMode);
HTTPClient::PendingResult pendingResult = HTTPClient::Get (IO::URI::URI ("https://httpbin.org/image/jpeg"),
HTTPClient::Options {}.SetOutputFile (filePtr));
pendingResult.Wait ();
auto result = pendingResult.AcquireResult ();
if (result.IsValue () && result->GetStatusCode () == HTTPClient::StandardStatusCode::OK) {
UInt64 size;
filePtr->GetDataLength (&size);
std::cout << "Received result with type " << result->GetContent ()->GetContentType () << " and size " << size << std::endl;
} else {
std::cout << "Unexpected result!" << std::endl;
}

Uploading a file

IO::Location fileLocation;
IO::fileSystem.GetSpecialLocation (IO::FileSystem::TemporaryFolder, &fileLocation);
fileLocation.AppendToLocal (IO::Name ("testfile_" + GS::Guid (GS::Guid::GenerateGuidSelector::GenerateGuid).ToUniString () + ".txt"));
HTTPClient::OutputFile filePtr = new IO::File (fileLocation, IO::File::OnNotFound::Create);
filePtr->Open (IO::File::OpenMode::ReadWriteMode);
filePtr->WriteBin ("Test", 4);
filePtr->Seek (IO::File::Start, 0);
GS::Owner<GS::IBinaryChannel> fileAdapter = GS::NewOwned<GS::IBinaryChannelAdapterForIChannel> (filePtr);
HTTPClient::PendingResult pendingResult = HTTPClient::Post (IO::URI::URI ("https://httpbin.org/post"),
GS::NewOwned<HTTPClient::Content> (fileAdapter.Pass ()));
pendingResult.Wait ();
auto result = pendingResult.AcquireResult ();
if (result.IsValue () && result->GetStatusCode () == HTTPClient::StandardStatusCode::OK)
std::cout << "File uploaded successfully" << std::endl;

Redirect

HTTPClient::PendingResult pendingResult = HTTPClient::Get (IO::URI::URI ("https://httpbin.org/redirect-to?url=https://graphisoft.com"));
pendingResult.Wait ();
auto result = pendingResult.AcquireResult ();
if (result.IsValue ())
std::cout << "Got successfully redirected to " << result->GetURI ().ToString ().ToCStr () << std::endl;

Connection error

HTTPClient::PendingResult pendingResult = HTTPClient::Get (IO::URI::URI ("https://doesnotexist.com/"));
pendingResult.Wait ();
auto result = pendingResult.AcquireResult ();
if (result.IsError () && result.GetError () == HTTPClient::ErrorCode::CouldntConnect)
std::cout << "Connection failed as expected!" << std::endl;
else
std::cout << "Unexpected result!" << std::endl;

Timeout

HTTPClient::PendingResult pendingResult = HTTPClient::Get (IO::URI::URI ("https://httpbin.org/delay/5"),
HTTPClient::Options {}.SetTimeoutMilliSeconds (1'000));
pendingResult.Wait ();
auto result = pendingResult.AcquireResult ();
if (result.IsError () && result.GetError () == HTTPClient::ErrorCode::Timeout)
std::cout << "Timeout occurred as expected!" << std::endl;
else
std::cout << "Unexpected result!" << std::endl;