2012-02-05 2 views
5

Я хотел бы предоставить API REST для моего приложения, используя веб-сервер Mongoose и предоставляя обработчики для разных запросов.Parse REST-запрос в C++

Пример запроса будет, как это (я только с помощью GET на данный момент, остальные HTTP глаголов придет позже):

GET /items -> returns a list of all items in JSON 
GET /item/by/handle/123456789 -> returns item that has handle 123456789 
GET /item/by/name/My%20Item -> returns item(s) that have the name "My Item" 

Что мне любопытно, как я должен выполнять разбор этих запросов. Я могу легко разобрать первый, так как это просто вопрос if(query.getURI() == "/items") return ....
Но для следующих двух запросов я должен манипулировать строками std:: совершенно по-другому, используя магию и смещения std::string::find(), чтобы перейти к аргументу.

В качестве примера, это реализация у меня есть для второго запроса:

size_t position = std::string::npos; 
std::string path = "/item/by/handle/"; 

if((position = query.getURI().find(path)) != std::string::npos) 
{ 
    std::string argument = query.getURI().substr(position + path.size()); 
    // now parse the argument to an integer, find the item and return it 
} 

Что делать, если я хочу «templatize» это; Значение: Я описываю путь и аргументы, которые я ожидаю впоследствии (целое число, строка, ....); и код автоматически генерируется для обработки этого?

Tl, доктор: Я хочу, чтобы иметь возможность обрабатывать запросы REST в C++ с чем-то вдоль этих линий:

registerHandler("/item/by/handle/[INTEGER]", myHandlerMethod(int)); 

Возможно ли это?

+0

Похоже, вам нужны регулярные выражения, найденные в boost или C++ 11. –

ответ

4

Скорее несексуальный, но простой подход заключается в простом использовании sscanf. Простите скорее C-подобный код. Обратите внимание, что это не обеспечивает тип синтаксиса, который вы ищете, но он не требует каких-либо библиотек, расширений или повышения.

Например,

 
int param; 
int a, b; 
char c[255]; 

/* recall that sscanf returns the number of variables filled */ 
if(1 == sscanf(query.getURI(), "/item/by/handle/%d", &param)) { 

    handler(param); 

} else if (3 == sscanf(query.getURI(), "/more/params/%d/%d/%s", &a, &b, &c)) { 

    anotherHandler(a, b, c); 

} else { 
    // 404 
} 
+2

Обратите внимание, что использование% s опасно для ввода пользователя, потому что оно не проверяет границы и может быть легко переполнено. Я предлагаю для приведенного выше примера: 'sscanf (query.getURI(),"/more/params /% d /% d /% 254s ", & a, & b, c)' – valenok

+0

Хорошая точка. Для тех, кто хочет предотвратить это, Kernighan и Pike имеют простое решение: http://stackoverflow.com/questions/1621394/how-to-prevent-scanf-causing-a-buffer-overflow-in-c – Tom

1

Хотя нагула через некоторый код Python, я обнаружил, что Flask фреймворк имеет particular way of parsing REST paths:

Вы объявляете путь:

@app.route('/post/<int:post_id>') 
def show_post(post_id): 
    # show the post with the given id, the id is an integer 
    return 'Post %d' % post_id 

И Flask создает все необходимое, чтобы дать вам целое число, в котором вы нуждаетесь.

Это именно то, что мне нужно, поэтому, я думаю, мне придется сделать это самостоятельно на C++.
Я получу ответ Тома, так как это актуально, и я предполагаю, что моя реализация будет немного похожа на его предложение (хотя я предпочитаю iostreams).

Я оставлю этот ответ здесь любому, кто скрывается.

+0

http: //expressjs.com/ также имеет аналогичную функцию. – Tom

+0

Вы в конечном итоге реализовали этот синтаксис в C++? - Если да, считаете ли вы открытым исходным кодом? :) – stackoverflowuser95

+0

Увы, нет.Я в конечном итоге изменил свою работу и нашел некоторые другие проблемы для решения. – Gui13