Search code examples
c++boosturlencodeboost-url

How to % encode comma , in query params with Boost.URL


Intro

In my program I have a Google Places API client and to build URL I use Boost.URL library:

#include <iostream>
#include <boost/url/src.hpp>
#include <boost/url/encode.hpp>
#include <boost/json/src.hpp>

...

boost::urls::url endpoint("https://maps.googleapis.com/maps/api/place/autocomplete/json");
auto params = endpoint.params();
params.append({"key", "PLACE_API_KEY" });
params.append({"input", "Tower" });
params.append({"radius", "500" });

auto location = std::make_pair(51.507351, -0.127758);
std::string locationString = std::to_string(location.first) + "," + std::to_string(location.secod);
params.append({"location", locationString});

std::cout << endpoint.encoded_target().substr() << '\n';

Problem

Unfortunately due to the URL RFC specification, it doesn't encode , (comma) symbol because it's reserved

So the code above print:

/maps/api/place/autocomplete/json?key=PLACE_API_KEY&input=Tower&radius=500&location=51.507351,-0.127758

If I replace , with %2C in locationString variable, the output will be:

/maps/api/place/autocomplete/json?key=PLACE_API_KEY&input=Tower&radius=500&location=51.507351%252C-0.127758

because % was encoded to %25

Question

Is there a way to percent-encode , in a query param value with Boost.URL API?


Solution

  • As you correctly analyse, the RFC requires the comma to be preserved as-given.

    It follows that you can give it as "%2C".

    I figured out by reversing the path:

    urls::url ep("https://maps.googleapis.com/maps/api/place/autocomplete/"
                 "json?key=PLACE_API_KEY&input=Tower&radius=500&location=51.507351%2C-0.127758");
    for (auto [k, v, h] : ep.params())
        std::cout << k << " -> " << v << " (" << std::boolalpha << h << ")" << std::endl;
    for (auto [k, v, h] : ep.encoded_params())
        std::cout << k << " -> " << v << " (" << std::boolalpha << h << ")" << std::endl;
    

    Which prints

    key -> PLACE_API_KEY (true)
    input -> Tower (true)
    radius -> 500 (true)
    location -> 51.507351,-0.127758 (true)
    key -> PLACE_API_KEY (true)
    input -> Tower (true)
    radius -> 500 (true)
    location -> 51.507351%2C-0.127758 (true)
    

    It follows, that appending to encoded_params should work:

    urls::param_pct_view p("location", "51.507351%2C-0.127758");
    endpoint.encoded_params().append(p);
    

    And indeed it does:

    Live On Compiler Explorer

    #include <iostream>
    #include <boost/url/src.hpp>
    #include <boost/url/encode.hpp>
    namespace urls = boost::urls;
    
    int main() {
        urls::url endpoint("https://maps.googleapis.com/maps/api/place/autocomplete/json");
    
        auto params = endpoint.params();
        params.append({"key", "PLACE_API_KEY"});
        params.append({"input", "Tower" });
        params.append({"radius", "500" });
    
        urls::param_pct_view p("location", "51.507351%2C-0.127758");
        endpoint.encoded_params().append(p);
    
        std::cout << endpoint << std::endl;
    }
    

    Prints

    https://maps.googleapis.com/maps/api/place/autocomplete/json?key=PLACE_API_KEY&input=Tower&radius=500&location=51.507351%2C-0.127758