Incorporate Response and RestHandler into core

Description

coldbox.system.RestHandler

New base class coldbox.system.RestHandler which you can inherit from or use our new restHandler annotation. This will give you access to our enhanced API utilities and the native response object.

It is highly suggested to use the inheritance chain as it is faster and you get code highlights from your editors like VS Code.

You can now build all of your api’s using the native response object like the rest templates, but now from the core directly. This Rest Handler gives you the following actions out of the box:

Core Actions

Purpose

aroundHandler()

Wraps all rest actions uniformly to provide consistency and error trapping.

onError()

An implicit error handler is provided just in case anything explodes in your restful actions. Sends an appropriate 500 error

onValidationException()

Traps any {{ValidationException }}and makes sure it sends the appropriate 400 response with the invalid data. Useful for using cbValidation

onEntityNotFoundException()

Traps any {{EntityNotFound }}or {{RecordNotFound }}exceptions and makes sure it send an appropriate 404 response. Useful for leveraging cborm or Quick ORM

onInvalidHTTPMethod()

Traps any invalid HTTP method security exception and sends the appropriate 405 not allowed response

onMissingAction()

Traps any invalid actions/resource called in your application and sends the appropriate 404 response

onAuthenticationFailure()

Traps InvalidCredentials exceptions and sends the appropriate 403 invalid credentials response. If you are using cbSecurity it will also verify jwt token expiration and change the error messages accordingly.

onAuthorizationFailure()

Action that can be used when a user does not have authorization or access to your application or code. Usually you will call this manually or from a security library like cbSecurity or cbGuard. It will send a 401 not authorized response.

onInvalidRoute()

Action that can be used as a catch all from your router so it can catch all routes that are invalid. It will send a 404 response accordingly.

onExpectationFailed()

Utility method for when an expectation of the request fails ( e.g. an expected parameter is not provided ). This action is called manually from your own handlers and it will output a 417 response back to the user.

AroundHandler in Detail

The aroundHandler() provided in the RestHandler will intercept all rest calls in order to provide consistency and uniformity to all your actions. It will try/catch for major known exceptions, time your requests, add extra output on development and much more. Here are a list of the features available to you:

  • Exception Handling

    • Automatic trapping of the following exceptions: InvalidCredentials, ValidationException, EntityNotFound, RecordNotFound

    • Automatic trapping of other exceptions

    • Logging automatically the exception with extra restful metadata

    • If in a development environment it will respond with much more information necessary for debugging both in the response object and headers

  • Development Responses

    • If you are in a development environment it will set the following headers for you:

      • x-current-route

      • x-current-routed-url

      • x-current-routed-namespace

      • x-current-event

  • Global Headers

    • The following headers are sent in each request

      • x-response-time : The time the request took in CF

      • x-cached-response : If the request is cached via event caching

The aroundHandler() is also smart in detecting the following outputs from a handler:

  • Handler return results

  • Setting a view or layout to render

  • Explicit renderData() calls

RequestContext Additions

  • getResponse()

    • Will get you the current prc.response object, if the object doesn’t exist, it will create it and set it for you

    • The core response object can be found here: coldbox.system.web.context.Response

Extending The RestHandler

If you would like to extend or modify the behavior of the core {{RestHandler }}then you will have to create your own base handler that inherits from it. Then all of your concrete handlers will inherit from your very own handler.

Extending The Response Object

The response object can be found here: coldbox.system.web.context.Response and the rest handler constructs it by calling the request context’s getResponse() method. The method verifies if there is a prc.response object and if it exists it returns it, else it creates a new one. So if you would like to use your very own, then just make sure that before the request you place your own response object in the prc scope.

Here is a simple example using a preProcess() interceptor in your config/Coldbox.cfc:

That’s it. Once that response object is in the prc scope, ColdBox will utilize it. Just make sure that your custom Response object satisfies the methods in the core one.

Activity

Show:
Luis Majano
March 30, 2020, 4:26 PM

Ok, just so I can clarify this. If an action is detected with the same as the exception.type then call that instead of the base one?

Eric Peterson
March 30, 2020, 9:58 PM

Instead of onError, correct. Again, this would be an enhancement for all handlers, not just this new rest handler.

Wil de Bruin
April 2, 2020, 7:27 PM

I see a default onValidationException() now which is nice. The only problem is the response messages is quite simple. If you want to use it combined with cbvalidation, you don’t want to lose this nice array of errormessages for each field. If you can return an array of validation error messages in the response keyed by field, you can build nice interfaces because your errors can refer to the correct input field

We solved it now by adding an extra errormessages array to the response object (instead of or additional to a simple errormessage field) and add something like this to the onValidationError method
    // add validation errors
var ErrorInfo =  deserializeJSON( arguments.exception.extendedInfo );     

for (var key in ErrorInfo) {       
for ( var eachError in Errorinfo[key] ) {         
if ( find( "validation.", eachError.message ) == 1 ) {           eachError.message = res.getResource(eachError.message);         }         prc.response.addError(eachError);   }     }

Of course we can still keep doing this, but some more support for validation errors would be very helpful.




Luis Majano
April 3, 2020, 12:10 AM

Will, but the error messages are serialized into the exception and presented as messages in the data though.

Wil de Bruin
April 3, 2020, 6:29 PM

Yes, I missed that one. Is indeed a better solution. So I am happy!

Assignee

Luis Majano

Reporter

Luis Majano

Labels

None

Components

Fix versions

Priority

Major
Configure