Writing JSON APIs : Part I – Creating a secure JSON API with Grails and Spring Security in 3 easy steps

16 / Nov / 2011 by Vivek Krishna 2 comments

We had a requirement in a recent project to expose some of the functionality we had via a JSON API. The functionality needed to be secure, as was the initial web interface which exposed the functionality. We were using Spring Security for the security aspect of our application.

The spring security plugin, together with a secured controller and a custom JSON marshaller(which overrides the default functionality of render as JSON method) gave us a very simple, yet elegant and powerful JSON API which was secure. Here are the three steps that we followed

1. Setting up Spring Security Plugin:

The first step is to set up Spring Security Plugin to expose our JSON based controllers to use Basic Authentication, instead of the standard web-based authentication. This is done by adding the lines given below in Config.groovy

[java]
//Enable Basic Auth Filter
grails.plugins.springsecurity.useBasicAuth = true
grails.plugins.springsecurity.basic.realmName = "JSON API Example"
//Exclude normal controllers from basic auth filter. Just the JSON API is included
grails.plugins.springsecurity.filterChain.chainMap = [
‘/json/**’: ‘JOINED_FILTERS,-exceptionTranslationFilter’,
‘/**’: ‘JOINED_FILTERS,-basicAuthenticationFilter,-basicExceptionTranslationFilter’
]
[/java]

More details about the authentication mechanism can be found here.
2. Adding a Controller with required actions:

Naturally, this is the next step. We added a controller which would expose the functionalities required(another reason why most of our logic should be in our services instead of controllers). A sample controller would look like this.

[java]
package jsonapi
import grails.plugins.springsecurity.Secured
import grails.converters.JSON
import com.intelligrape.example.json.Book

@Secured(["ROLE_USER"])
class JsonController {
def getBooks = {
render Book.list() as JSON
}
}
[/java]

3. Customizing the Marshaller to change the way some properties like enums are rendered:

We had to change the way some of the properties like enums were going to be rendered. We just had to render the property name and the id of the enum. So instead of a JSON map like

[java]

"genre":{"enumType":"com.intelligrape.example.json.Book$Genre","name":"FICTION"}

[/java]

we needed

[java]

"genre":"FICTION"

[/java]

I sought help from David Bower’s post and created my own custom Domain Class Marshaller for JSON with a modification to just use the Enum value if the property happened to be an enum. This is a very powerful feature because it allows us to customize the way in which we want to render the values when creating a JSON or XML document from our classes. We can even customize it to have an excludes list in our domain class where we can specify the properties to be excluded while constructing our JSON or XML

With this, we had a JSON API ready in very little time. I have extracted the functionality into a small example application, which has been shared on Github.

Yet another example of how simple grails has made it easy for developers.

FOUND THIS USEFUL? SHARE IT

comments (2)

  1. Vivek

    You are right. REST was probably the wrong word to use here. I should probably have used “JSON API” instead.

    I had a look at the plugin and it’s awesome. We had to incorporate a few more things like having separate property groups, which I’ll be touching upon in part II.

    Updating the title. 🙂

    Reply
  2. Matthias

    Well… there’s nothing REST in the way you described your API. REST is all about resources and not actions so “getBooks” is no in the RESTful spirit. I know it first-hand that getting your mind set to working with resources instead of actions for someone coming from the WS-* world is hard. But hey, learning and twisting your mind are the two things we programmers like to do best, right?

    If you’d like to expose an entity in a fully restful manner you can use the json-rest-api plugin.

    Reply

Leave a Reply to Vivek Cancel reply

Your email address will not be published. Required fields are marked *