I have a function, Post()
, that takes two arguments - a std::string
path to listen for requests on, and a std::function<void(Request &, Response &)>
to handle an incoming request. Note that I can't modify Post()
.
For example:
m_server.Post("/wallet/open", [this](auto req, auto res)
{
std::cout << req.body << std::endl;
}
I'm trying to pass the request through a middleware function, and then forward on to the handler function.
The handler function and the middleware function are member functions. The setup of the Post() binding takes place within a member function of the same class.
This works:
m_server.Post("/wallet/open", [this](auto req, auto res){
auto f = std::bind(&ApiDispatcher::openWallet, this, _1, _2);
middleware(req, res, f);
});
However, I'm hooking up a reasonable amount of requests, and it would be nice to abstract this into a function, so we can just call, for example
m_server.Post("/wallet/open", router(openWallet));
I managed to get something like this working, but I can't figure out how to make it work when using member functions. This works great if everything is a free function:
const auto router = [](auto function)
{
return std::bind(middleware, _1, _2, function);
};
m_server.Post("/wallet/open", router(openWallet))
.Post("/wallet/keyimport", router(keyImportWallet))
.Post("/wallet/seedimport", router(seedImportWallet))
.Post("/wallet/viewkeyimport", router(importViewWallet))
.Post("/wallet/create", router(createWallet))
However, my attempt to get it working for member functions doesn't work, and I can't really figure out what the error message is telling me:
const auto router = [](auto function)
{
return std::bind(&ApiDispatcher::middleware, _1, _2, function);
};
m_server.Post("/wallet/open", router(&ApiDispatcher::openWallet))
.Post("/wallet/keyimport", router(&ApiDispatcher::keyImportWallet))
.Post("/wallet/seedimport", router(&ApiDispatcher::seedImportWallet))
.Post("/wallet/viewkeyimport", router(&ApiDispatcher::importViewWallet))
.Post("/wallet/create", router(&ApiDispatcher::createWallet))
The router function by itself works. I think the issue is I'm not calling the handler functions on this
. I tried doing this instead:
m_server.Post("/wallet/open", router(std::bind(&ApiDispatcher::openWallet, this, _1, _2)));
But then I get an error about "Wrong number of arguments for pointer-to-member".
Here's a minimal example to replicate the problem:
#include <iostream>
#include <string>
#include <functional>
using namespace std::placeholders;
class ApiDispatcher
{
public:
void middleware(std::string req, std::string res, std::function<void(std::string req, std::string res)> handler)
{
// do some processing
handler(req + " - from the middleware", res);
}
void dispatch()
{
const auto router = [](auto function)
{
return std::bind(&ApiDispatcher::middleware, _1, _2, function);
};
/* Uncommenting this line breaks compilation */
// Post("/wallet/open", router(&ApiDispatcher::openWallet));
}
void openWallet(std::string req, std::string res)
{
std::cout << req << std::endl;
}
void Post(std::string method, std::function<void(std::string req, std::string res)> f)
{
// wait for a http request
f("request", "response");
}
};
int main()
{
ApiDispatcher server;
server.dispatch();
}
Thanks. Sorry the post was so long.
Your router function needs to return a function that will call the specified member function with a specific instance of the class.
Or, and I missed this originally, to route everything through the middleware function, easiest I could find was.
Or, if you'd rather use bind, then you'll have to force the inner bind to be a function first, and do.