crow icon indicating copy to clipboard operation
crow copied to clipboard

Support multiple methods for same URL...

Open jamiebullock opened this issue 8 years ago • 13 comments

Is there any way to define routes for multiple methods for the same URL, e.g. for /foo I have POST, GET DELETE etc

If I do:

CROW_ROUTE(app, "/foo")
    .methods("POST"_method) (...)

CROW_ROUTE(app, "/foo")
    .methods("PUT"_method) (...)

I get the runtime error:

libc++abi.dylib: terminating with uncaught exception of type std::runtime_error: handler already exists for /foo

jamiebullock avatar Aug 14 '17 16:08 jamiebullock

A quick glance reveals (happy to make a mistake) that HTTP method is not a part of a route and it does not seem easy to alter this behavior. It is a shame because having multiple methods for an URL is essential for a REST framework. Especially for such a nice as crow ...

ilejn avatar Sep 26 '17 07:09 ilejn

Defining multiple methods for the same URL is supported by Crow.

CROW_ROUTE(app, "/foo") .methods("POST"_method, "PUT"_method) (...)

boodkb avatar Oct 08 '17 20:10 boodkb

Sure, right. The question is if it is possible to have different handlers for different HTTP methods and same URL. In flask one can have

@app.route('/api/v1/table', methods=['GET'])
def test():
    return jsonify(d)
@app.route('/api/v1/table', methods=['POST'])
def test1():
   # something

Is it supported in crow?

ilejn avatar Oct 08 '17 21:10 ilejn

I just test it and it works !

// Test multiple method on same URL
CROW_ROUTE(app,"/hello/<int>")
    .methods(crow::HTTPMethod::Get)
([](int count){
    if (count > 100)
        return crow::response(400);
    std::ostringstream os;
    os << "GET " << count << " bottles of beer!";
    return crow::response(os.str());
});
CROW_ROUTE(app,"/hello/<int>")
    .methods(crow::HTTPMethod::Put)
([](int count){
    if (count > 100)
        return crow::response(400);
    std::ostringstream os;
    os << "PUT " << count << " bottles of beer!";
    return crow::response(os.str());
});

lkoeller avatar May 17 '18 12:05 lkoeller

@lkoeller your code is not working in my application

Any solutions for this?

tommy87 avatar Mar 25 '20 08:03 tommy87

@lkoeller your code is not working in my application

Any solutions for this?

crow version? What does 'not working' mean? Details, may be.

ilejn avatar Mar 25 '20 08:03 ilejn

When running the code i get the message:

terminate called after throwing an instance of 'std::runtime_error' what(): handler already exists for /hello/

This happens when calling the CROW_ROUTE the second time.

The code is build from the master branch

Edit: running on a Ubuntu 18.04 System

tommy87 avatar Mar 25 '20 12:03 tommy87

After some testing i found a working solution:

CROW_ROUTE(app,"/hello").methods(crow::HTTPMethod::Get, crow::HTTPMethod::Put)
    ([](const crow::request& req){
        switch (req.method)
        {
            case crow::HTTPMethod::Put:
                std::cout << "PUT " << std::endl;
                return crow::response(200, "Method: PUT");;

            case crow::HTTPMethod::Get:
                std::cout << "Get " << std::endl;
                return crow::response(200, "Method: GET");;

            default:
                std::cout << "unhandled " << std::endl;
                return crow::response(200, "Method: unhandled");
        }
    });

tommy87 avatar Mar 25 '20 15:03 tommy87

I suggest that you recheck that your crow contains https://github.com/ipkn/crow/commit/b7360a2bacb426401636a1e76e5e713ed0c3b0fc . master has it of course. The behaviour with 'handler already exists' is expected for an older version.

ilejn avatar Mar 25 '20 16:03 ilejn

I don't understand why my example code is not working. Just tested again with examples/helloworld.cpp

`#include "crow.h"

int main() { crow::SimpleApp app;

CROW_ROUTE(app, "/")
([]() {
    return "Hello world!";
});
// Test multiple method on same URL
CROW_ROUTE(app,"/hello/<int>")
    .methods(crow::HTTPMethod::Get)
([](int count){
    if (count > 100)
    return crow::response(400);
    std::ostringstream os;
    os << "GET " << count << " bottles of beer!";
    return crow::response(os.str());
});
CROW_ROUTE(app,"/hello/<int>")
    .methods(crow::HTTPMethod::Put)
([](int count){
    if (count > 100)
    return crow::response(400);
    std::ostringstream os;
    os << "PUT " << count << " bottles of beer!";
    return crow::response(os.str());
});

app.port(18080).run();

}`

And it works without runtime error. Compiled non outdated ubuntu 14.04 LTS gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)

~/Project/Crow/crow-master/build$ make helloworld Scanning dependencies of target helloworld [100%] Building CXX object examples/CMakeFiles/helloworld.dir/helloworld.cpp.o Linking CXX executable helloworld [100%] Built target helloworld

~/Project/Crow/crow-master/build/examples$ ./helloworld & [1] 2296 (2020-03-25 16:44:04.122387) [INFO ] Crow/0.1 server is running at 0.0.0.0:18080 using 1 threads (2020-03-25 16:44:04.122537) [INFO ] Call app.loglevel(crow::LogLevel::Warning) to hide Info level logs.

~/Project/Crow/crow-master/build/examples$ curl -X GET localhost:18080/hello/10 (2020-03-25 16:47:00.350426) [INFO ] Request: 127.0.0.1:51280 0x7f001c000960 HTTP/1.1 GET /hello/10 (2020-03-25 16:47:00.350489) [INFO ] Response: 0x7f001c000960 /hello/10 200 0 GET 10 bottles of beer!

~/Project/Crow/crow-master/build/examples$ curl -X PUT localhost:18080/hello/100 (2020-03-25 16:47:12.494063) [INFO ] Request: 127.0.0.1:51284 0x7f001c001d80 HTTP/1.1 PUT /hello/100 (2020-03-25 16:47:12.494104) [INFO ] Response: 0x7f001c001d80 /hello/100 200 0 PUT 100 bottles of beer!

lkoeller avatar Mar 25 '20 16:03 lkoeller

i recheck everything and i am using the latest version of crow, including the commit https://github.com/ipkn/crow/commit/b7360a2bacb426401636a1e76e5e713ed0c3b0fc

Edit: we using the "crow_all" build. And i will recheck if we maybe have some special building flags. I think i will get the information's tomorrow.

tommy87 avatar Mar 25 '20 16:03 tommy87

But what i don't understand is when looking into the function void add(const std::string& url, unsigned rule_index) in file include/crow/routing.h

Th exception is thrown in the line

if (nodes_[idx].rule_index)
                throw std::runtime_error("handler already exists for " + url);

And this make sense, the nodes are build in a way, that the same url always leads to the same idx. And when building the same url twice (HTTPMethod is not used for build up the nodes) it must crash at this point. So i wonder how the code that lkoeller postet can work, it should alwas crash or miss i something?

tommy87 avatar Mar 25 '20 17:03 tommy87

Today i get the information, that we haven't build the project by ourself. We download the "crow_all.h" from the Release build v1 which is from Sept. 2017

I will build the code from the master and test it again

tommy87 avatar Mar 26 '20 10:03 tommy87