在卡萨布兰卡实施多个 API

Implementing multiple API in casablanca

我正在查看这段代码,它使用 casablanca 实现了一个简单的 JSON 服务器。到目前为止,我还没有找到更好的例子。作者似乎对每个 API 使用了不同的 HTTP 方法,当服务器应该有很多 API 时,这可能会成为一个问题。应该如何解决这个问题?这是否意味着我需要多个 http_listeners ?

#include <cpprest/http_listener.h>
#include <cpprest/json.h>

using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;

#include <iostream>
#include <map>
#include <set>
#include <string>
using namespace std;

#define TRACE(msg)            wcout << msg
#define TRACE_ACTION(a, k, v) wcout << a << L" (" << k << L", " << v << L")\n"

map<utility::string_t, utility::string_t> dictionary;
typedef std::vector<std::pair<utility::string_t, json::value>> field_map;
/* handlers implementation */

void handle_get(http_request request)
{
    TRACE(L"\nhandle GET\n");

    field_map answer;

    for (auto const & p : dictionary)
    {
        answer.push_back(make_pair(p.first, json::value(p.second)));
    }

    request.reply(status_codes::OK, json::value::object(answer));
}

void handle_request(http_request request,
    function<void(json::value &, field_map &)> action)
{
    field_map answer;

    request
        .extract_json()
        .then([&answer, &action](pplx::task<json::value> task) {
        try
        {
            auto & jvalue = task.get();

            if (!jvalue.is_null())
            {
                action(jvalue, answer);
            }
        }
        catch (http_exception const & e)
        {
            wcout << e.what() << endl;
        }
    })
        .wait();

    request.reply(status_codes::OK, json::value::object(answer));
}

void handle_post(http_request request)
{
    TRACE("\nhandle POST\n");

    handle_request(
        request,
        [](json::value & jvalue, field_map & answer)
    {
        for (auto const & e : jvalue.as_array())
        {
            if (e.is_string())
            {
                auto key = e.as_string();

                auto pos = dictionary.find(key);
                if (pos == dictionary.end())
                {
                    answer.push_back(make_pair(key, json::value(L"<nil>")));
                }
                else
                {
                    answer.push_back(make_pair(pos->first, json::value(pos->second)));
                }
            }
        }
    }
    );
}

void handle_put(http_request request)
{
    TRACE("\nhandle PUT\n");

    handle_request(
        request,
        [](json::value & jvalue, field_map & answer)
    {
        for (auto const & e : jvalue.as_object())
        {
            if (e.second.is_string())
            {
                auto key = e.first;
                auto value = e.second.as_string();

                if (dictionary.find(key) == dictionary.end())
                {
                    TRACE_ACTION(L"added", key, value);
                    answer.push_back(make_pair(key, json::value(L"<put>")));
                }
                else
                {
                    TRACE_ACTION(L"updated", key, value);
                    answer.push_back(make_pair(key, json::value(L"<updated>")));
                }

                dictionary[key] = value;
            }
        }
    }
    );
}

void handle_del(http_request request)
{
    TRACE("\nhandle DEL\n");

    handle_request(
        request,
        [](json::value & jvalue, field_map & answer)
    {
        set<utility::string_t> keys;
        for (auto const & e : jvalue.as_array())
        {
            if (e.is_string())
            {
                auto key = e.as_string();

                auto pos = dictionary.find(key);
                if (pos == dictionary.end())
                {
                    answer.push_back(make_pair(key, json::value(L"<failed>")));
                }
                else
                {
                    TRACE_ACTION(L"deleted", pos->first, pos->second);
                    answer.push_back(make_pair(key, json::value(L"<deleted>")));
                    keys.insert(key);
                }
            }
        }

        for (auto const & key : keys)
            dictionary.erase(key);
    }
    );
}

int main()
{
    http_listener listener(L"http://localhost/restdemo");

    listener.support(methods::GET, handle_get);
    listener.support(methods::POST, handle_post);
    listener.support(methods::PUT, handle_put);
    listener.support(methods::DEL, handle_del);

    try
    {
        listener
            .open()
            .then([&listener]() {TRACE(L"\nstarting to listen\n"); })
            .wait();

        while (true);
    }
    catch (exception const & e)
    {
        wcout << e.what() << endl;
    }

    return 0;
}

是的,您可以根据 URI 设置多个 http_listeners。效果很好。