Oat++ No mapping for HTTP-method

88 Views Asked by At

I am building an endpoint that requires 2 query parameters: email_address and token, the issue I am seeing is that when I make the following call from Postman every other click is an error:

http://localhost:8000/handshake/is_valid_user_token?param=p

The error message:

server=oatpp/1.3.0
code=404
description=Not Found
message=No mapping for HTTP-method: '{', URL: ''

Code:

ENDPOINT("POST", "handshake/is_valid_user_token/*", isValidUserToken,
       REQUEST(std::shared_ptr<IncomingRequest>, request))
{
    auto tail = request->getPathTail();
    auto queryParams = oatpp::network::Url::Parser::parseQueryParams(tail);

    auto emailAddress = queryParams.get("email_address");
    auto userToken = queryParams.get("token");
    if (!emailAddress || !userToken)
    {
        return ApiResponseFactory::createResponse (
                ApiResponseStatus::CODE_401, "Missing email or token");
    }

    return ApiResponseFactory::createResponse (
            ApiResponseStatus::CODE_401, "OK");
}

I am using Oat++ 1.3.0, this issue manifests itself on both a Mac, Linux and Windows (Visual Studio project). Any suggestions would be gratefully accepted as I appear to be doing it as expected. Used this for reference

Could the controller object be going out of scope, thus causing the incomplete error message?

Here is the code related to it:

void AddApiController(
        std::shared_ptr<ApiEndpointController> controller)
{
    provider.router>addController(controller);
}

How it's called:

auto controller = std::make_shared<
            HandshakeApiController> ();
AddApiController(controller);
1

There are 1 best solutions below

2
VonC On BEST ANSWER

The issue might not be directly related to the controller object going out of scope, but rather to how the endpoint is defined and potentially how the HTTP method and URL are being parsed or matched by Oat++'s router.

Given the endpoint definition and the error message, it is important to make sure the HTTP request matches the expected format defined by your endpoint. Your endpoint is expecting a POST request, but the URL you have provided from Postman is more typical of a GET request with query parameters.
That mismatch could be the source of the "No mapping for HTTP-method" error, as Oat++ cannot find a POST route matching the given URL format.

Verify that you are sending a POST request from Postman, and includes the email_address and token as query parameters in the URL. Since your endpoint is designed to handle POST requests, using a GET request might cause routing issues.
Your endpoint path includes a wildcard (*), which is intended to capture the rest of the path as a tail. However, your actual use case involves query parameters, not path parameters. Make sure this aligns with your intended design.
Query parameters should be extracted directly from the request object, not from the path tail. Oat++ provides a way to get query parameters directly without needing to parse the path tail.

Your endpoint code could handle query parameters in a POST request with:

ENDPOINT("POST", "handshake/is_valid_user_token", isValidUserToken,
         REQUEST(std::shared_ptr<IncomingRequest>, request))
{
    auto queryParams = request->getQueryParameters();

    auto emailAddress = queryParams.get("email_address");
    auto userToken = queryParams.get("token");
    if (!emailAddress || !userToken) {
        return createResponse(Status::CODE_400, "Missing email or token");
    }

    // Perform your token validation logic here

    return createResponse(Status::CODE_200, "OK");
}

Regarding the controller management, the way you are registering the controller seems correct, and as long as the AddApiController(controller); call is part of your application's initialization logic and controller remains in scope (e.g., not being destructed immediately after initialization), it should not be the source of the issue.


The issue appears to occur if I need to return a response, so if email or token isn't valid. Accessing the query parameters no longer fails. I have changed the call from POST to GET.

That (from POST to GET)... is different! It indicates the problem might not be with the request type or how query parameters are handled, but how responses are generated and sent back in error cases.
Make sure the methods used to generate responses, particularly in error cases, are correct and follow Oat++'s expected practices.

For instance:

#include <oatpp/web/server/api/ApiController.hpp>
#include <oatpp/core/macro/codegen.hpp>
#include <oatpp/core/macro/component.hpp>

#include OATPP_CODEGEN_BEGIN(ApiController) ///< Begin Codegen

class HandshakeApiController : public oatpp::web::server::api::ApiController {
public:
    HandshakeApiController(OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
        : oatpp::web::server::api::ApiController(objectMapper) {}

    ENDPOINT("GET", "handshake/is_valid_user_token", isValidUserToken,
             QUERY(String, emailAddress, "email_address"),
             QUERY(String, userToken, "token"))
    {
        // Check for missing or invalid email or token
        if (emailAddress->empty() || userToken->empty()) {
            // Use createResponse method to generate a proper error response
            auto response = createResponse(Status::CODE_400, "Missing or invalid email or token");
            // Optionally, you can set additional headers or customize the response further
            response->putHeader(Header::CONTENT_TYPE, "text/plain");
            return response;
        }

        // If email and token are valid, proceed with your logic
        // For demonstration, let's assume validation is successful
        return createResponse(Status::CODE_200, "Email and token are valid");
    }
};

#include OATPP_CODEGEN_END(ApiController) ///< End Codegen

The ENDPOINT annotation defines a GET request for the path handshake/is_valid_user_token. It uses the QUERY parameters to directly obtain email_address and token from the query string.
Before proceeding with any business logic, the endpoint checks if the emailAddress or userToken is empty (considered invalid for this example). If either is missing or invalid, it generates an error response. For error cases, createResponse(Status::CODE_400, "Missing or invalid email or token") creates a response with a 400 Bad Request status code and a plain text message indicating the nature of the error. The putHeader method is used to set the Content-Type header of the response, although this is optional and depends on the needs of your application.
If validation passes, a 200 OK response is returned with a success message. That part of the code would typically include your validation logic and potentially return different messages or data based on the outcome.


The only way to resolve this is to define a body type, regardless of if I am going to use it, which seems wrong

True: the Oat++'s design might require certain endpoint configurations to process requests correctly. That could include defining a body type for POST or PUT requests, even if the body is not utilized within the endpoint. That way, all aspects of the HTTP request are accounted for in the routing and processing stages.

If defining an unused body type feels counterintuitive or leads to cluttered code, you could consider alternative approaches. For example, if the issue comes from the framework's expectations for certain HTTP methods, you could explicitly ignore the body in the endpoint implementation or use a lightweight placeholder DTO that does not affect your application logic but satisfies the framework's requirements.