1

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?

CAMOBAP
  • 5,523
  • 8
  • 58
  • 93

1 Answers1

2

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
sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    Awesome troubleshooting! Thanks a lot! I just found out that `"51.507351%2C-0.127758"` can be replaced with `boost::urls::encode("51.507351,-0.127758", boost::urls::unreserved_chars)` – CAMOBAP Jun 10 '23 at 05:53
  • 1
    That deserves to be its own answer – sehe Jun 10 '23 at 09:24