Minimal boost::beast HTTPS client JSON example

This example uses boost::beast to make a HTTPS request to ipify.org and parses the response using boost::json.

#include <iostream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <boost/beast/core.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/json.hpp>
#include <openssl/ssl.h>

namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
namespace ip = boost::asio::ip;
namespace ssl = boost::asio::ssl;
namespace json = boost::json;
using tcp = boost::asio::ip::tcp;

int main()
{
    std::string host = "api64.ipify.org";

    // Initialize IO context
    net::io_context ioc;
    ssl::context ctx(ssl::context::tlsv13_client);
    ctx.set_default_verify_paths();

    // Set up an SSL context
    beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx);
    stream.set_verify_mode(ssl::verify_none);
    stream.set_verify_callback([](bool preverified, ssl::verify_context& ctx) {
        return true; // Accept any certificate
    });
    // Enable SNI
    if(!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) {
        beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()};
        throw beast::system_error{ec};
    }
    // Connect to the HTTPS server
    ip::tcp::resolver resolver(ioc);
    get_lowest_layer(stream).connect(resolver.resolve({host, "https"}));
    get_lowest_layer(stream).expires_after(std::chrono::seconds(30));

    // Construct request
    http::request<http::empty_body> req{http::verb::get, "/?format=json" , 11};
    req.set(http::field::host, host);
    req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);

    // Send the request
    stream.handshake(ssl::stream_base::client);
    http::write(stream, req);

    // Receive the response
    beast::flat_buffer buffer;
    http::response<http::dynamic_body> res;
    http::read(stream, buffer, res);
    
    // Parse the JSON response
    json::error_code err;
    json::value j = json::parse(buffers_to_string(res.body().data()), err);

    std::cout << "IP address: " << j.at("ip").as_string() << std::endl;

    if (err) {
        std::cerr << "Error parsing JSON: " << err.message() << std::endl;
    }

    // Cleanup
    beast::error_code ec;
    stream.shutdown(ec);

    if (ec == net::error::eof) {
        ec = {};
    }
    if (ec) {
        throw beast::system_error{ec};
    }

    return 0;
}

Compile using

g++ -g -o http-example http-example.cpp -lcrypto -lssl -lboost_json

Example output:

IP address: "2a01:c22:6f8c:ef00:f0bb:a8a8:9c00:ff49"