五. RESTful APIs
1. 创建一个endpoint
需要工具:Talend API Tester(以前叫Restlet):Chrome 插件
crow默认使用get方法,添加对其他HTTP方法的支持。
在main.cpp增加支持HTTP方法路由:
CROW_ROUTE(app, "/rest_test").methods(HTTPMethod::Post, HTTPMethod::Get, HTTPMethod::Put)
([](const crow::request& req, crow::response& res)
{
string method=method_name(req.method);
res.set_header("Content-Type", "text/plain");
res.write(method+" rest_test");
res.end();
});
在路由中先增加Post方法,在Talend测试Post,有响应:
测试Post,无响应:
增加哪个方法,哪个方法就有相应。
2. 解析路径
目前已可通过email查询,增加使用name查询,在main.cpp加一个contact/<fistname/<latname>路由,修改getView,随着修改contacts和contact/<email>路由:
// **************modify**************
void getView(response& res, const string& filename, context& x)
{
res.set_header("Content-Type", "text/html");
auto text=load_unsafe(filename + ".html").render_string(x);
res.write(text);
res.end();
}
// **************modify**************
CROW_ROUTE(app, "/contact/<string>")
([&collection](const request& req, response& res, string email)
{
auto doc=collection.find_one(make_document(kvp("email", email)));
//crow::json::wvalue dto;
crow::mustache::context dto;
dto["contact"]=json::load(bsoncxx::to_json(doc.value().view())) ;
getView(res, "contact", dto);;
});
// **************modify**************
// ***************add****************
CROW_ROUTE(app, "/contact/<string>/<string>")
([&collection](const request& req, response& res, string firstname, string lastname)
{
auto doc=collection.find_one(make_document(kvp("firstName", firstname), kvp("lastName", lastname)));
if (!doc)
{
return notFound(res,"Contact");
}
// crow::json::wvalue dto;
crow::mustache::context dto;
dto["contact"]=json::load(bsoncxx::to_json(doc.value().view())) ;
getView(res, "contact", dto);;
});
// ***************add****************
// **************modify**************
CROW_ROUTE(app, "/contacts")
([&collection](const request& req, response& res)
{
mongocxx::options::find opts;
opts.skip(9);
opts.limit(10);
auto docs=collection.find({}, opts);
crow::json::wvalue dto;
vector<crow::json::rvalue> contacts;
contacts.reserve(10);
for (auto doc : docs)
{
contacts.push_back(json::load(bsoncxx::to_json(doc)));
}
dto["contacts"] = contacts;
getView(res, "contacts", dto);
});
// **************modify**************
在浏览器查看:
在浏览器中通过add查询结果,在main.cpp加add一个路由:
CROW_ROUTE(app, "/add/<int>/<int>")
([](const request& req, response& res, int a, int b)
{
res.set_header("Content-Type", "text/plain");
ostringstream os;
os<<"Interger: "<<a<<" + " << b<< " = "<<a+b<<endl;
res.write(os.str());
res.end();
});
CROW_ROUTE(app, "/add/<double>/<double>")
([](const request& req, response& res, double a, double b)
{
res.set_header("Content-Type", "text/plain");
ostringstream os;
os<<"Double: "<<a<<" + " << b<< " = "<<a+b<<endl;
res.write(os.str());
res.end();
});
CROW_ROUTE(app, "/add/<string>/<string>")
([](const request& req, response& res, string a, string b)
{
res.set_header("Content-Type", "text/plain");
ostringstream os;
os<<"String: "<<a<<" + " << b<< " = "<<a+b<<endl;
res.write(os.str());
res.end();
});
注意数据类型的先后顺序一定是int, double, string,否则不起作用。在浏览器查看:
3. 读取查询字符串
增加查询firstname | lastname,显示contact信息,增加一个query路由,修改main.cpp:
CROW_ROUTE(app, "/query")
([](const request& req, response& res)
{
auto firstname=req.url_params.get("firstname");
auto lastname=req.url_params.get("lastname");
ostringstream os;
os << "Hello "<< (firstname? firstname: "")
<<" "<<(lastname? lastname: "")<<endl;
res.set_header("Content-Type", "text/plain");
res.write(os.str());
res.end();
});
4. 转换成json数据
从crow返回json类型的数据,增加api/contacts路由:
CROW_ROUTE(app, "/api/contacts")
([&collection](const request& req)
{
mongocxx::options::find opts;
opts.skip(9);
opts.limit(10);
auto docs=collection.find({}, opts);
vector<crow::json::rvalue> contacts;
contacts.reserve(10);
for (auto doc : docs)
{
contacts.push_back(json::load(bsoncxx::to_json(doc)));
}
crow::json::wvalue dto;
dto["contacts"] = contacts;
return crow::response{dto};
});
浏览器查看:
5. 练习:创建一个endpoint
- 修改api/contacts路由,在里面使用skip和limit两个参数
- 若skip是valid,设置MongoDB skip选项为skip值,否则,设为0
- 若limit是valid,设置MongoDB limit选项为limit值,否则,设为10
设置skip=3, limit=5,效果:
6. 解决方案
- 创建两个字符串代表查询参数
auto skip_val=req.url_params.get("skip");
auto limit_val=req.url_params.get("limit");
- 把字符串转换成整数
- 设置skip和limit选项
opts.skip(skip_val? stoi(skip_val): 0);
opts.limit(limit_val? stoi(limit_val): 10);