[coldbox-4.1] RESTful Action Routing vs this.allowedMethods and onInvalidHTTPMethod Interception

Hi,

I have a question regarding the difference between the use of this.allowedMethods in the handler`

this.allowedMethods = {
login = “POST”,
index = “GET”
};

`

and the addtion of the actions within the routes.cfm

`

with(pattern="/auth", handler=“Auth”)

.addRoute(pattern="/logout", action={GET=“logout”})
.addRoute(pattern="/login", action={POST=“login”})

.endWith();

`

In this case the /auth/login route must be hit with a POST http method. When I have the action={POST=“login”} portion defined on the route the “onInvalidHTTPMethod” function doesn’t fire. If I remove this from the route the “allowedMethods” kicks in and the onInvalidHTTPMethod function fires and I handle the response gracefully in my BaseRemoteHandler.cfc

My initial instinct was that these would both fire the same interception point. Is there a different method that fires when the HTTP verb doesn’t match the route’s defined action so I can return a restful response versus the following error.

405 : Oopsy! Something went wrong!Event: N/A

Routed URL: auth/login/
Layout: N/A (Module: )
View: N/A
Timestamp: 06/30/2015 12:05:37 PM

The restrictions in the route definition will cause that route to not even be matched, meaning the SES interceptor keeps looking until it finds another route that matches. Once a matching route is located, then the allowedmethods are looked at and if the HTTP verb does not apply an error is thrown.

These are two separate checks performed at different levels of event execution. The route-to-event mapping happens very early in the request as part of the onRequestCapture interception point and the allowed verbs check happens later as the event is being run.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

Thanks Brad. After sending I realized that it was definitely getting caught by the SES interceptor.

https://github.com/ColdBox/coldbox-platform/blob/master/system/interceptors/SES.cfc#L142

`

getUtil().throwInvalidHTTP(className=“SES”, detail=“The HTTP method used: #HTTPMethod# is not valid for the current executing resource. Valid methods are: #aRoute.action.toString()#”, statusText=“Invalid HTTP method: #HTTPMethod#”, statusCode=“405”);

`

It looks like all I have to do is wire up my onException() method in my BaseRemoteHandler.cfc to marshal the error thrown by the Util.cfc -> throwInvalidHTTP() to marshall it back as JSON effectively matching the response I’m generating in my onInvalidHTTPMethod() interception point.

Thanks for your help as always.

~Tim

I am having the same issue. Would you care to go through what you had to do Tim to get this fixed?

In my ‘/config/Routes.cfm’ file I have the following rules:

`
addRoute(
pattern = ‘/tasks/:id-numeric’,
handler = ‘tasks’,
action = {
GET = ‘view’,
PUT = ‘update’,
DELETE = ‘remove’
}
);

addRoute(
pattern = ‘/tasks’,
handler = ‘tasks’,
action = {
POST = “create”,
GET = “list”
}
);
`

While in my handler, I have this:

this.allowedMethods = { list = "GET", view = "GET", create = "POST", update = "PUT", remove = "DELETE" };

The ‘onInvalidHTTPMethod’ never fires, just like yours.

To add to my comment above, this is the actual response that gets sent to the client, instead of a JSON response.

Your DELETE method requires a numeric ID in the URL params. Are you providing that in the URL?

I think the issue me and Tim have here is that the http verb is wrong. You are not supposed to be able to hit the ‘/tasks’ url with DELETE, just GET and POST. The Invalid HTP Methos needs to be caught and raised through ColdBox’s ‘onInvalidHTTPMethod’, but it never fires.

Ah, sorry. I didn’t read the subject closely enough. I just tested this out on a 4.1.0 API and you’re right. onInvalidHTTPMethod() is not firing because the SES interceptor doesn’t even test for that method. It’s just configured to throw an error. This is a bug. Starting at line 130 in coldbox/system/interceptors/SES.cfc:

if( structKeyExists(aRoute,"action") && isStruct(aRoute.action) ){
    // Verify HTTP method used is valid, else throw exception and 403 error
    if( structKeyExists(aRoute.action,HTTPMethod) ){
        aRoute.action = aRoute.action[HTTPMethod];
        // Send for logging in debug mode
        if( log.canDebug() ){
            log.debug("Matched HTTP Method (#HTTPMethod#) to routed action: #aRoute.action#");
        }
    }
    else{
         
        getUtil().throwInvalidHTTP(className="SES",
                                   detail="The HTTP method used: #HTTPMethod# is not valid for the current executing resource. Valid methods are: #aRoute.action.toString()#",
                                   statusText="Invalid HTTP method: #HTTPMethod#",
                                   statusCode="405");
    }
}

I’ve raised a bug report for this one: https://ortussolutions.atlassian.net/browse/COLDBOX–479

Thanks for the ticket Jon, we’ll see what Luis says about it.

I think the core of the issue is that the SES interceptor and the actual handler execution happen on opposite ends of the request lifecycle and have no real overlaps or interplay even though they have similar configuration bits (valid verbs, etc) The SES bit runs on request capture and long before the actual handler CFC is even located or instantiated (if needed). The verb mappings that you configure in your route serve only to help filter what routes will be matched. At that point in the request, the event is just a string that’s been built up that specifies what handler and action will be run later on when the Coldbox gets around to it. Therefore, if the criteria for a route are matched, the request never even gets to the point of actually dealing with the handler CFC. The this.allowedmethods bit happens outside of SES (can apply to the “old” URL style) and is a check run once the handler service is about to execute the actual action.

So I guess I said all that to mean that your ticket may make a good deal of sense, but I believe there is a significant technical hurdle at this point for the SES interceptor to have the ability to introspect the actual handler since at that point in the request, the handler location hasn’t even been resolved (default convention, external, module, etc)

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

Brad,

JMO, but I’m not sure why the SES interceptor needs to handle the verb errors at all. It’s primary job is simply to assemble the routing and then pass that on to the framework. Since that error is already being handled in Controller.cfc, it seems like a duplication of effort to evaluate the verbs in the interceptor too.

Jon

That’s possible, but let’s say you use a verb that isn’t mapped to an action. What action should the SES interceptor assemble? The default one? The alternative would be that the route is simply not matched at all I suppose.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

I see what you’re saying. You can’t avoid verb evaluation altogether because of the way routing is configured. You could simply pass the first matched route (or last matched, if you’re in a loop) that didn’t include that verb. The framework would then handle the rest and fire the onInvalidHTTPMethod() functions.

The only drawback to that would be if you were using different handlers for multiple versions of the same route, which had different onInvalidHTTPMethod() functions. For me that’s never the case, as I always extend all API handlers off a base API handler, which includes the error handling in the explicit methods.

One of the changes we slated for ColdBox 4 (that didn’t make it in) was to rewrite the SES interceptor to be a core service since it’s really the standard for URL routing these days (unlike many years ago when it was introduced). If we incorporated it better into the core I think it might help resolve some of the issues with the URL routing being so decoupled from the resolution of handlers. (This was also in include moving /config/routes.cfm over to the standard CFC approach, possibly with a better DSL for declaration)

Another feature we talked about before ColdBox 4 development started was the ability to define routes via annotations right in your handlers. That would certainly require a tighter integration, not to mention registering routes based on the handlers when the framework started up. Anyway, those things are always in the back of my mind since I still want to see us realize these changes in a future version of ColdBox.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com