cpr
cpr copied to clipboard
Enhance "template metaprogramming magic" for HTTP methods
Is your feature request related to a problem?
Library provides good experience by providing variadic template interface in HTTP methods, however, you can't template-ly select HTTP method to call.
For example, you have myGet function:
template <class... Ts>
cpr::Response myGet(Ts&&... ts) {
return cpr::Get(cpr::Bearer{"ACCESS_TOKEN"}, cpr::Header{{"Content-Type", "application/json; charset=utf-8"}});
}
It's great, the headers will always be in the request. However, you also need the same wrapper for POST method. I can duplicate code, but it's lame.
The other way is to provide the function to myGet (ignore the name):
template <typename F, class... Ts>
cpr::Response myGet(F f, Ts&&... ts) {
return f(std::forward<Ts>(ts)..., cpr::Bearer{"ACCESS_TOKEN"}, cpr::Header{{"Content-Type", "application/json; charset=utf-8"}});
}
The solution will not make you happy:
cpr::Response r = myGet(cpr::Post<cpr::Url, cpr::Body, cpr::Bearer, cpr::Header>, cpr::Url{"http://www.httpbin.org/post?a=b"}, cpr::Body{"{\"a\": true}"});
You have to specify template parameters for cpr::Post and it looks worse than making a duplicate.
Possible Solution
Add HTTPMethod and a universal template to make a request.
#include <cpr/cpr.h>
namespace cpr {
enum class HTTPMethod {
kGet,
kHead,
kPost,
kPut,
kDelete,
kOptions,
kPatch,
};
template <HTTPMethod method, typename... Ts>
Response Request(Ts&&... ts) {
cpr::Session session;
cpr::priv::set_option(session, std::forward<Ts>(ts)...);
using enum HTTPMethod;
if constexpr (method == kGet) {
return session.Get();
} else if constexpr (method == kHead) {
return session.Head();
} else if constexpr (method == kPost) {
return session.Post();
} else if constexpr (method == kPut) {
return session.Put();
} else if constexpr (method == kDelete) {
return session.Delete();
} else if constexpr (method == kOptions) {
return session.Options();
} else if constexpr (method == kPatch) {
return session.Patch();
} else {
static_assert(method == kGet, "Unknown method");
}
}
}
template <cpr::HTTPMethod method, class... Ts>
cpr::Response MyResponse(Ts&&... ts) {
return Request<method>(std::forward<Ts>(ts)..., cpr::Bearer{"ACCESS_TOKEN"}, cpr::Header{{"Content-Type", "application/json; charset=utf-8"}});
}
int main() {
cpr::Response r = MyResponse<cpr::HTTPMethod::kPost>(cpr::Url{"http://www.httpbin.org/post?a=b"}, cpr::Body{"{\"a\": true}"});
std::cout << r.text << std::endl;
}
Alternatives
- compile-time if
- duplicated code for each method
Additional Context
No response
@GitSparTV I like this approach. Would you like to create a PR for this?
@COM8
Sure