sunnuntai 21. joulukuuta 2014

Grails REST API with JSON and nested list of objects

In the web there's quite a lot of discussion about how to get JSON presentation of the domain objects using Grails and it's controllers. The part that seemed to be missing was how to be able to post JSON which has nested lists/elements to system and save those successfully.

But first, lets move a bit back from REST API to "normal" GSP pages + controllers combination. There was quite nice example of that at: http://www.objectpartners.com/2012/10/04/an-approach-to-processing-dynamic-one-to-many-forms-with-grails-2-1/. It's for a bit older Grails, but works with newer versions after changing plugin versions to valid ones. So, with that post we get working application, that's able to save parent object (Team), and it save list of child objects (Player) at the same time.

At this point it could be thought, that it's very easy to use JSON for both getting data from system and putting data to it. First part is actually very easy: Just one import and order Grails to render response as JSON:

import grails.converters.JSON
...
render team as JSON (instead of redirect(action: 'show', params: [id:team.id]))
If/when there's need for field selection or redering only part of the information, custom marshaller can be used. E.g. http://grails.org/plugin/marshallers.

Saving data with JSON

When testing saving with just single objects (without nested properties) all worked like a charm. Grails can parse JSON directly to domain object, which can be just save. Problems arise when there's nested list. This kind of save just thows error about ids:
| Error 2014-12-20 19:20:16,127 [http-bio-8080-exec-9] ERROR errors.GrailsExceptionResolver  - AssertionFailure occurred
 when processing request: [POST] /junk/api/rest
null id in junk.Player entry (don't flush the Session after an exception occurs). Stacktrace follows:
Message: null id in junk.Player entry (don't flush the Session after an exception occurs)
    Line | Method
->>  195 | doFilter  in grails.plugin.cache.web.filter.PageFragmentCachingFilter
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|     63 | doFilter  in grails.plugin.cache.web.filter.AbstractFilter
|   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
|    615 | run       in java.util.concurrent.ThreadPoolExecutor$Worker
This error comes to console/log, but saving of Team still succeeds with Hibernate 3. With Hibernate4 whole save is failed, which is kind of better solution.

When comparing Player objects (which clearly were the reason for this error), the reason came quite clear. The POST from GSP-page added "team" attribute to players :
<junk.Player@1ba14c1b firstName=first lastName=last position=position deleted=false errors=grails.validation.ValidationErrors: 0 errors $changedProperties=null id=null version=null team=junk.Team : (unsaved)>
while JSON POST left team as null:
junk.Player@76f8539e firstName=first lastName=last position=position deleted=false errors=grails.validation.ValidationErrors: 0 errors $changedProperties=null id=null version=null team=null>
Solution for this was explicitly connect this new Team to all Players, which allowed save to make it's job:
team.players.each {it.team = team} 

Complete working example (for Grails 2.3.8) can be found at https://github.com/Hi-Fi/writetable-example-with-grails.

 
 

sunnuntai 19. tammikuuta 2014

Review: Robot Framework Test Automation by Sumit Bisht

As mentioned in previous post, I got possibility to review Robot Framework Test Automation -book written by Sumit Bisht. I actually finished the reading already in December, but remembered to write review now.


I was quite keen to get the book, because I really haven't read much "IT things" from books, but directly from Internet. Same thing with Robot Framework (RF). Same time I also have acknowledged, that even though RF id kind of advertised to be for the non-technical people, too, the material is offering both worlds (technical and non-technical).

So, about the book. First, when I opened the book (got PDF version) I was quite surprised how short it is (99 pages). And this was even bigger surprise, that there's only about half of the book for the "beginners" (meaning: for "non-developers" in a sense). Other half is briefly labeled being about extending framework, and last 20 pages are reserved for index and advertisements.

The chapters from 1 to 3 and 5 offer new RF users brief introduction to framework and how it can be used in different ways (different test file forms, different ways to initialize variables etc.). Also some things about good way to write automated tests. Problem might be, that there's time to time more little details than flowing text, which might be hard for non-technical or non-experienced user of RF.

Personally I have used RF almost more as Java implementation than with Python (because of it's easier integration to CI with Maven). There was some mentions in the book about Java-version, but nothing about Maven. Also CI usage was mentioned once in reporting chapter. Yes, CI server can collect reports, but more important part is that it can run the tests. And setting up that run would have been more useful than mentioning (normal)  functionality of CI server being able to store old builds.

From here we get to the most problematic chapter, number 4, which is "Extending the Framework". Chapter actually just lists couple of libraries that are made for Robot Framework, and not really "extension writing" which I was expecting. 2 biggest problems with the data provided (if we forget extension writing part at this point) was Selenium2Library (no mentions, that normal version doesn't work with Java, or that there's different version to be used with Jython and Maven builds) and Sikuli (almost half of the chapter telling how to test with it or create custom Sikuli library).

Finally I'd say that book might be good for some people to get overview about RF, but rel usage can't be done with that being only source of information.