workshop: creating restful api’s with grails and spring security (gr8conf 2014)
DESCRIPTION
In this talk I will cover how to create a REST API using Grails 2.3 to support single-page applications, exploring all the possible alternatives. I will also explain how to integrate Spring Security using the spring-security-rest plugin I recently created, to implement a stateless, token-based, RESTful authentication. Code will be available at http://bit.ly/restful-codeTRANSCRIPT
Álvaro Sánchez-Mariscal Web Architect - odobo
@alvaro_sanchez
Creating RESTful API’s with Grails and Spring Security
About me• Passionate software developer.
• Worked at IBM BCS, BEA Systems and Sun Microsystems.
• Founded Salenda in 2005.
• Working now at Odobo as Web Architect.
• Living between Madrid and Gibraltar.
• HTML5 games platform for:
• Game developers.
• Casinos.
• Check out https://play.odobo.com and try for free!
About the workshop• Requirements:
• Grails 2.3.x SDK.
• A text editor / IDE.
• Internet connection.
• Try to complete the steps with the information provided.
• If you struggle, ask me :)
• If you don’t want my help :(, some tips are available at http://bit.ly/restful-<step>
• Slides available at http://bit.ly/restful-slides.
• Code will be at http://bit.ly/restful-code.
5
Step #1• Create a new application and install the following
plugins: • :spring-security-rest:1.3.4 • :functional-spock:0.7
• Add the following dependency: • runtime 'com.github.groovy-wslite:groovy-wslite:0.8.0'
• Remove the plugins we don’t need: • jquery • resources
• Disable Spring Security (we’ll use it later).
6
Step #2• Create the first functional test:
• GameSpec • “it returns a list of games in JSON” • Check that /games returns application/
json with a JSON body.
• Use wslite and send Accept header equal to application/json.
• ./grailsw test-app functional:
7
Step #3• Create Game domain class:
• A game has a name.
• Annotate it with @Resource(uri=‘/games’).
• Grab some game names from http://play.odobo.com and add some instances in BootStrap.
• ./grailsw test-app functional:
8
Step #4• Write tests for the others HTTP methods:
• POST: send a JSON payload to /games and assert on status code and Location header.
• PUT: send a JSON with a new name to /games/XX, then a GET on /games/XX. Assert that the name is changed.
• DELETE: send a request to /games/XX. Assert on status code. Then send a GET on /games/XX. Assert on status code.
9
Step #5• Create a Category domain class.
• A category has a name.
• A game can have many categories.
• Annotate it with @Resource(uri=‘/categories’, readOnly=true)
• Look at play.odobo.com and add the games to their correspondent categories in BootStrap.
10
Step #6• Write a CategorySpec to make sure it’s read only.
• Modification endpoints have to return 405.
• Run url-mappings-report and examine the result.
11
Step #7• Remove attributes from @Resource annotation.
• Setup the following mappings in URL mappings, using resources attribute:
• “/categories”• “/games”
• “/categories”
• Run url-mappings-report again and examine the result.
• Make sure tests are still passing.
12
Step #8• Test nested resource in CategorySpec:
• Pick a game with more than one category.
• Assert that /games/XX/categories returns only those categories.
13
Step #9• Create a GameController and CategoryController.
• Extending RestfulController.
• Defining JSON and XML response formats.
• Implementing the default constructor.
• Grails documentation, chapter 8.1.5.1.
• Remove @Resource annotations.
• Refactor CategorySpec:
• Leave only the nested resource test (should fail).
14
Step #10• Override listAllResources and countResources in
CategoryController.
• They will be called from parent’s index()
• Figure out param names by inspecting URL mappings report.
• Add a test to CategorySpec to assert that /categories returns all of them.
• Make sure the nested resource test passes.
15
Step #11• Get rid of the class attribute in the JSON
responses:
• Use JsonRenderer and JsonCollectionRenderer in resources.groovy.
• Grails documentation chapter 8.1.6.1.
• Make sure tests are passing.
• Test the new JSON rendering for games, categories and nested categories.
• It should fail when rendering the categories of a game.
16
Step #12• Register custom marshallers in BootStrap.
• Remove the renderers from resources.groovy.
• Grails documentation chapter 8.1.6.2.
• Make sure all tests are passing.
17
Step #13• Implement HAL rendering:
• Remove ‘xml’ response format in controllers, and add ‘hal’.
• Register HalJsonRenderer and HalJsonCollectionRenderer in resources.
• Remove custom marshallers from BootStrap.
• Write some tests using application/hal+json as Accept header.
• @Ignore the ‘class’ ones.
18
Step #14• Setup Spring Security.
• Take a look at http://bit.ly/restful-14.
• Annotate your controllers with @Secured(['ROLE_USER'])
• Now all tests are failing.
19
Step #15• Test authentication:
• Make a POST request to /api/login sending a JSON payload like: {“username”:”user”, “password”: “password”}
• Assert that a token is generated.
• Refactor the other tests to pass this token as an X-Auth-Token header.
Thanks!Álvaro Sánchez-Mariscal
Web Architect - odobo @alvaro_sanchez