2012-02-05 18 views
5

Chciałbym udostępnić interfejs REST API w mojej aplikacji, używając serwera WWW Mongoose i udostępniając moduły obsługi dla różnych zapytań.Analizowanie składni zapytania REST w C++

Przykładem zapytania byłoby tak (jestem tylko za pomocą GET do momentu, reszta czasowników HTTP przyjdzie później):

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" 

Co jestem ciekaw jest jak należy wdrożyć parsowanie tych zapytań. Mogę łatwo przetworzyć pierwszy, ponieważ jest to po prostu kwestia if(query.getURI() == "/items") return ....
Ale przy następnych dwóch zapytaniach muszę manipulować ciągami std:: w zupełnie inny sposób, używając magii i przesunięć std::string::find(), aby uzyskać argument.

Jako przykład, jest to implementacja mam na drugie zapytanie:

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 
} 

Co jeśli chcę „templatize” to; znaczenie: opisuję ścieżkę i argumenty, których spodziewam się później (liczba całkowita, ciąg znaków, ...); i kod jest generowany automatycznie, aby obsłużyć to?

Tl; dr: Chcę być w stanie obsługiwać zapytania do odpoczynku w C++ z czegoś wzdłuż tych linii:

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

to jest możliwe?

+0

Wygląda na to, że potrzebujesz wyrażeń regularnych, jak w boost lub C++ 11. –

Odpowiedz

4

Raczej nie seksowne, ale proste podejście byłoby po prostu użyć sscanf. Wybacz kod raczej podobny do C. Uwaga: nie zapewnia to oczekiwanej składni, ale nie wymaga żadnych bibliotek, rozszerzeń ani zwiększenia.

Na przykład

 
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

Należy zauważyć, że używanie% s jest niebezpieczne dla danych wprowadzanych przez użytkownika, ponieważ nie sprawdza granic i może być łatwo nadpisane. Sugeruję dla powyższego przykładu: 'sscanf (query.getURI(),"/more/params /% d /% d /% 254s ", & a, & b, c)' – valenok

+0

Dobra rada. Dla tych, którzy chcą temu zapobiec, Kernighan i Pike mają proste rozwiązanie: http://stackoverflow.com/questions/1621394/how-to-prevent-scanf-causing-a-buffer-overflow-in-c – Tom

1

Podczas żerowania przez jakiegoś kodu Pythona, znalazłem, że ramy Flask internetowa ma particular way of parsing REST paths:

zadeklarować ścieżkę tak:

@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 

A Flask tworzy wszystko, czego potrzeba, aby dać ci liczbę całkowitą, jakiej potrzebujesz.

To jest dokładnie to, czego potrzebuję, więc myślę, że będę musiał zrobić to sam w C++.
Dostanę odpowiedź Toma, ponieważ jest to istotne i wydaje mi się, że moja implementacja będzie wyglądać trochę tak, jak sugeruje (choć wolę preferować iostreams).

Zostawię tę odpowiedź tutaj każdemu, kto się czai.

+0

http: //expressjs.com/ również ma podobną funkcję. – Tom

+0

Czy wprowadziłeś tę składnię w C++? - Jeśli tak, czy rozważyli Państwo otwarcie go? :) – stackoverflowuser95

+0

Niestety, nie.Skończyło się na zmianie mojej pracy i znalazłem kilka innych problemów do rozwiązania. – Gui13