Monthly Archives: July 2013

Spring localized exception handling in REST API

In today’s post i’ll share with you the way we’re handling Internationalization (i18n) and Localization (L10n) in our REST API which is based on Spring MVC (3.2.3.RELEASE).

Our front-end web client is an SPA (Single Page Application) built using AngularJS framework and occasionally it needs to handle Java exceptions messages thrown by the back-end. The way it has been implemented is that it intercepts JSON error responses, wraps them in a pre-defined web page template and displays to the user in a unified and nice way.

“Localization” of back-end related error messages happens …at the back-end level.

 

After this quick intro let’s get familiar with following two definitions:

  • Internationalization – process of designing software applications so that they can be adapted to various languages and regions without engineering changes.
  • Localization – process of adapting internationalized applications for a specific region or language by adding locale-specific components and translating text.

OK, this is how message bundles look like:

// messages.properties
exception.npe=Unrecognized error: We're sorry.
(...)

and the project view so you get a feel on how maven-managed multi-module project is structured (i use IntelliJ IDEA)

Spring REST API

 

The ‘resourceBundle’ spring bean is located in ‘spring-locale-context.xml’

<bean id="resourceBundle"
      class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
      p:basename="classpath:locale/messages"
      p:cacheSeconds="5"
      p:defaultEncoding="UTF-8" />

 

As you can see i’m using ‘ReloadableResourceBundleMessageSource‘ which i prefer over ‘ResourceBundleMessageSource‘ – here’s why (according to Spring framework spec.)

  • ResourceBundleMessageSource – MessageSource implementation that accesses resource bundles using specified basenames. This class relies on the underlying JDK’s ResourceBundle implementation, in combination with the JDK’s standard message parsing provided by MessageFormat. This MessageSource caches both the accessed ResourceBundle instances and the generated MessageFormats for each message. It also implements rendering of no-arg messages without MessageFormat, as supported by the AbstractMessageSource base class. The caching provided by this MessageSource is significantly faster than the built-in caching of the java.util.ResourceBundle class. Unfortunately, java.util.ResourceBundle caches loaded bundles forever: Reloading a bundle during VM execution is not possible. As this MessageSource relies on ResourceBundle, it faces the same limitation. Consider ReloadableResourceBundleMessageSource for an alternative that is capable of refreshing the underlying bundle files.
  • ReloadableResourceBundleMessageSource – Spring-specific MessageSource implementation that accesses resource bundles using specified basenames, participating in the Spring ApplicationContext‘s resource loading. In contrast to the JDK-based ResourceBundleMessageSource, this class uses Properties instances as its custom data structure for messages, loading them via a PropertiesPersister strategy from Spring Resource handles. This strategy is not only capable of reloading files based on timestamp changes, but also of loading properties files with a specific character encoding. It will detect XML property files as well. In contrast to ResourceBundleMessageSource, this class supports reloading of properties files through the "cacheSeconds" setting, and also through programmatically clearing the properties cache. Since application servers typically cache all files loaded from the classpath, it is necessary to store resources somewhere else (for example, in the “WEB-INF” directory of a web app). Otherwise changes of files in the classpath will not be reflected in the application. This MessageSource implementation is usually slightly faster than ResourceBundleMessageSource, which builds on ResourceBundle – in the default mode, i.e. when caching forever. With “cacheSeconds” set to 1, message lookup takes about twice as long – with the benefit that changes in individual properties files are detected with a maximum delay of 1 second. Higher “cacheSeconds” values usually do not make a significant difference.

 

Now, let’s make our resourceBundle accessible to exception handlers:

public class AbstractExceptionHandler {

    @Autowired
    private ReloadableResourceBundleMessageSource resourceBundle;

    public ReloadableResourceBundleMessageSource getResourceBundle() {
        return resourceBundle;
    }

    public void setResourceBundle(ReloadableResourceBundleMessageSource resourceBundle) {
        this.resourceBundle = resourceBundle;
    }

}

 

Create an MVC REST Controller:

@Controller
@RequestMapping(value = "/users")
public class UserController {

    @Autowired
    private UserService service;

    /**
     * Handling GET request to retrieve all {@link User}'s
     * @return Collection<User> a collection of users
     */
    @RequestMapping(method = RequestMethod.GET)
    public @ResponseBody
    Collection<User> getUsers() {
        return service.findAllUsers();
    };

}

 

…and an exception handler that will intercept (NPE in this case) exceptions thrown by the controller:

@ControllerAdvice
public class BusinessExceptionHandler extends AbstractExceptionHandler {

    @ExceptionHandler(NullPointerException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody DefaultErrorMessage handleNullPointerException() {

        String error = getResourceBundle().getMessage("exception.npe", null, Locale.getDefault());

        return new DefaultErrorMessage("RS00230", "SYSTEM_ERROR", error);

    }

}

 

As you can see above, I did two things:

  • fed the error string with exception.npe message that comes from the message bundle and used Locale.getDefault()
  • and defined a custom DefaultErrorMessage which basically is a POJO send over to the client as a JSON response which looks like this:
{
  "code" : "RS00230",
  "status" : "SYSTEM_ERROR",
  "errors" : [ "Unrecognized error: We're sorry." ]
}

 

Hope you find this brief example helpful. Cheers!

 

 

Resources:

AngularJS custom HTTP headers in resource service

Recently i had to make an HTTP call from the browser (client-side) using JavaScript / AngularJS to a REST API (server-side) and retrieve data. Since the authentication mechanism of the API required a security token to be passed over with the request, i studied AngularJS specs on how to do it best. Basically, there are two ways to do it, either as a:

  1. query parameter, or
  2. custom HTTP header

 

Because i didn’t wanted the security token to appear anywhere in the logs or debugging console (like on the picture below, in case of making use of option 1 just mentioned, ie. query parameter), i decided on passing the token as a custom (there’s no standard header for passing tokens) HTTP header.

AngularJS query API token

 

Since i use Yeoman (app workflow/scaffolding tool) i noticed that through a standard angular-template used for generating an application scaffolding, you’re getting dependency on angular framework in version 1.0.7 (last stable version as of writing this post). Although this is what you would generally expect (stable version, not a snapshot), the problem is that angular documentation for $resource service (which is what i prefer to use over $http service), does not mention the possibility of sending HTTP headers (regarding $http – i think of it as a solution for rather “general purpose AJAX calls”).

 

One way to set HTTP headers is by accessing $httpProvider.defaults.headers configuration object, like this:

$httpProvider.defaults.headers.get['API-Token'] = 'vy4eUCqpQmGoeWsnHKwCQw'

(more documentation about that you’ll find here), but this way you’re modifying $httpProvider globally which may not be what you exactly want.

 

Google search came with help and i found issue 736, which acknowledges that “$resource should support custom http headers”, but it is with the (unstable) release 1.1.3 where this feature is supported for sure (maybe earlier “unstable” versions do support it too, haven’t checked that actually, but definitely none of the stable versions do, as of today).

 

So, what is it that you have to do in order to introduce an unstable version of AngularJS into your project managed by Bower?

bower install angular-unstable
bower install angular-resource-unstable

(dependency on angular-resource.js is required in order for it to work).

 

Now, the only other thing left to do is to update your index.html file accordingly (to make use of proper version of libraries) :

<script src="bower_components/angular-unstable/angular.js"></script>
<script src="bower_components/angular-resource-unstable/angular-resource.js"></script>

 

…and you can start adding custom HTTP headers in your code:

angular.module('usersService', ['ngResource'])
    .factory('User', function($resource, api-token) {
        var User = $resource('http://api.test.com\\:8080/1.0/users', { }, {
            query: {
                method: 'GET',
                isArray: true,
                headers: { 'API-Token': api-token }
            }
        });
        return User
    });

 

Hope this short post will save some of your time 🙂 Cheers!

 

 

Resources:

AngularJS, Karma and debugging unit tests in WebStorm or IntelliJ IDEA

Recently i had to debug few Javascript unit tests in WebStorm IDE and was wondering if it’ll be as easy of an experience as it is in case of Java and IntelliJ IDEA (where i originally come from).

WebStorm 6 doesn’t offer native Karma test runner support (ver 7 which is currently in EAP, does – details here), but using a NodeJS plug-in you can execute any kind of NodeJS application (Karma included).

 

OK, what we’ll need in this exercise is following:

  • One of two JetBrains IDE’s, either:
    • WebStorm (great for JavaScript code) or
    • IntelliJ IDEA (Java’s no. 1 IDE)
  • NodeJS plug-in installed in the IDE:
    • WebStorm comes having it already pre-installed
    • in case of IDEA (Ultimate version, because Community Edition doesn’t have the required JavaScript plug-in for it to work, see here) the plug-in can be downloaded from here.
  • NodeJS environment which can be downloaded from here.
  • Karma (old name Testacular) test runner installed (“npm install -g karma”) that allows running unit (or E2E) tests in one of these browsers:
    • Chrome
    • ChromeCanary
    • Firefox
    • Opera
    • Safari (only Mac)
    • PhantomJS
    • IE (only Windows)
  • Chrome/Firefox “JetBrains IDE Support” extension (required for debugging) that can be downloaded from here.

 

Installing the NodeJS plug-in in IntelliJ IDEA:

  • Open “Settings” dialog (File -> Settings… in the menu bar)
  • Select “Plugins” (under “IDE Settings”)
  • Click “Browse repositories…”
  • Click “Download and Install” on the “NodeJS” plug-in
  • Press “Restart” when asked, to restart the IDE

 

Configuring IDE to execute Karma test in NodeJS using the plug-in:

  • Open the Run/Debug Configuration dialog by selecting “Edit Configurations” in the Run area of the main toolbar of WebStorm.
  • Add the following two configurations (picture below):
    • “Karma Run”: to perform a “single run” of your unit tests.
    • “Karma Server”: to start Karma in “Continuous Integration” mode (automatic re-runs of your tests whenever files change).
  • Configure the “Karma Run” configuration:
    • Press the “+” button in the top-left of the “Run/Debug Configurations” dialog.
    • Select “Node.js” in the list
    • Fill in the following fields:
      • Name: enter “Karma Run”
      • Path to Node: absolute path to NodeJS executable (i.e. “c:\NodeJS\node.exe”)
      • Working Directory: absolute path of your AngularJS application (i.e. “C:\MyProjects\AngularApp”)
      • Path to Node App JS File: Should point to the (globally, ie. -g) installed “Karma” NodeJs executable (i.e. “C:\Users\…\AppData\Roaming\npm\node_modules\karma\bin\karma”)
      • Application Parameters: run karma.conf.js –single-run –no-auto-watch –reporters dots
    • Press “Apply”
  • Configure the “Karma Server” configuration:
    • Essentially take the same steps as while configuring “Karma Run”, changing only the following:
      • Name: enter “Karma Run”
      • Application Parametersstart karma.conf.js –no-single-run –auto-watch –reporters dots
  • Configure the “Karma Debug” configuration to allow debugging of Karma unit tests
    • Press the “+” button in the top-left of the “Run/Debug Configurations” dialog.
    • Select “JavaScript Debug -> Remote” in the list
    • Fill in the following fields:
      • Name: enter “Karma Debug”
      • URL to openhttp://localhost:8100/debug.html (port number depends on your configuration in karma.conf.js file (passed as an “Application Parameter” in the previous two configurations)
      • Browser: chose either Chrome or Firefox
      • Set the “Remote URL” field to point to “http://localhost:8100/base

        Karma Debug configuration in IntelliJ WebStorm

 

Finally, run your “Karma Server” configuration and while it’s working in the background (–auto-watch mode), set debugging breakpoints in your code and fire “Karma Debug” configuration.

That’s it. Hope this small guide turns out to be helpful.

 

Resources: