Tuesday, June 28, 2016

Rest API Docs Swagger

I had a lot of problems trying to get swagger to work, finally found this resource which sort of worked for me.
First I started getting

Error creating bean with name 'com.github.rahulsom.swaggydoc.ApiController': Injection of autowired dependencies failed;
This was fixed by adding the following to depenedencies
compile "org.grails:grails-dependencies"

The test UserController, User domain worked. But when I added a very simple class of my won it would render on the http://localhost:8080/api page but clicking it did not bring down it operations.

Okay found the reason. For Swaggy to work you need a few crucial things:
  • Your controller needs the @Api annotation

@Api(value = 'ApiFile', description = 'Anything')
class ApiFileTypeController extends RestfulController {
    static responseFormats = ['json', 'xml']
    ApiFileTypeController() {
        super(ApiFileType)
    }
}
  • Your UrlMapping needs the url for the resource

class UrlMappings {

    static mappings = {
        "/$controller/$action?/$id?(.$format)?"{
            constraints {
                // apply constraints here
            }
        }
        "/filetypes"(resource: 'apiFileType')

        "/"(view:"/index")
        "500"(view:'/error')
        "404"(view:'/notFound')
    }
}

Monday, June 27, 2016

Sunday, June 26, 2016

Grails3 Twitter Bootstrap installing a theme

So Grails 3 and twitter boostrap, where is the bootstrap plugin and how do I install a theme?
First there is no plugin (well there are some plugins that seem to modify your scaffoldin, fields plugin) but Grails 3 has bootstrap as standard really.

But you have bought a theme like Material and want to get it into your app.

Get Theme

So download the Material theme unpack it and run the setup (npm install).
Lets say we want to install the jQuery light theme your theme directory should have a structure similar to:
 --Export
     |
     +--AngularJs
     |
     +--Documenation
     |
     +--jQuery
          |
          +--dark
          |
          +--light
               |
               +--css
               |
               +--fonts
               |
               +--img
               |
               +--js
               |
               +--less
               |
               +--media
               |
               +--node_modules
               |
               +--vendors
               |
               Loads html

Copy the entire light directory into your grails directory at the assets location [app]/grails-app/assets
Rename it to material.

If you run the app, you should be able to access your theme material, with the urls like
http://localhost:8080/assets/index.html
http://localhost:8080/assets/css/demo.css

Material.gsp

Now take a material theme html page, like index.html and copy it into your [app]grails-app/views/layouts directory calling it something like material.gsp.

Now lets edit the material.gsp to take out content and render our grails app in there. Find the


<section id="content">

And replace all the content in it so it looks like this. Basically nothing but including a body

<section id="content">
     <g:layoutBody/>
</section>

Replace all links to css and js includes directories to point to the new assets directory in material.gsp so these links

<link href="vendors/bower_components/fullcalendar/dist/fullcalendar.min.css" rel="stylesheet">
<script src="vendors/bower_components/jquery/dist/jquery.min.js"></script>

Become these

<link href="/assets/vendors/bower_components/fullcalendar/dist/fullcalendar.min.css" rel="stylesheet">
<script src="/assets/vendors/bower_components/jquery/dist/jquery.min.js"></script>

Use

Now we just need tell our page to use this new layout so go to your index.gsp and make the head look as follows (change the content)
<head>
    <meta name="layout" content="material"/>
Now your index.gsp page should render in this new theme

Next Steps

This just quickly shows you how to get a theme in, you still need to change the navigation and add whatever content you want, but it is a start

Sunday, June 19, 2016

Grails fiels f:table f:all

Grails uses the field plugin to generate templates for your GSP.
So for instance your gsp with
<fieldset class="form">
    <f:all bean="project"/>
</fieldset>
Will show a form for all the fields on a Bean.
And the following will show a table view

<f:table collection="${projectList}" />
But what if you want to override the styling, that is easy!
But where do you start, it took me a while to find the default templates that are used, you can find them in the plugin.

So right here is the tables one:
<table>
<thead>
<tr>
<g:each in="${domainProperties}" var="p" status="i">
<g:set var="propTitle">${domainClass.propertyName}.${p.name}.label</g:set>
<g:sortableColumn property="${p.name}" title="${message(code: propTitle, default: p.naturalName)}" />
</g:each>
</tr>
</thead>
<tbody>
<g:each in="${collection}" var="bean" status="i">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<g:each in="${domainProperties}" var="p" status="j">
<g:if test="${j==0}">
<td><g:link method="GET" resource="${bean}"><f:display bean="${bean}" property="${p.name}" displayStyle="${displayStyle?:'table'}" /></g:link></td>
</g:if>
<g:else>
<td><f:display bean="${bean}" property="${p.name}" displayStyle="${displayStyle?:'table'}" /></td>
</g:else>
</g:each>
</tr>
</g:each>
</tbody>
</table>

Wednesday, June 15, 2016

Debugging Grails 3 in Intellij 2016

I got stuck trying to edit run/debug configuration in Intellij to get my Grails project to debug. There where lots of posts about forks etc, etc.
But it is much simpler than that.

Just go to

grails-app/init/webtracker.api/Application

and right click on Application and select Debug 'Application.main()'

There we go
Intellij will remember these and you can get to them quick in the Build menu

Tuesday, June 14, 2016

Grails log your hibernate queries

To log the Hibernate queries that your app is making merely add these to your logback.groovy
logger('org.hibernate.SQL', DEBUG, ['STDOUT'], false)
logger('org.hibernate.type', TRACE, ['STDOUT'], false)
The false eliminated duplicate entries

Legacy DB, Grails & Domain Classes

When having to build Grails apps around a legacy DB, this plugin is a great start.

The DB reverse engineer plugin (works with Grails 3)

It is a good idea to create a Integration test to just check you can access these tables. The integration test will be run on your development envrionment and you will need to have some data in there. Be careful obviously as it is bad practise to rely on existing data, but this helped me get all the mappings properly wired up.
Start with something as simple as:
package com.webtracker.api.prodcat

import com.webtracker.api.Company
import com.webtracker.api.Project
import com.webtracker.api.WpActivationKey
import grails.test.mixin.integration.Integration
import grails.transaction.Rollback
import spock.lang.Specification

/**
 * Sanity domain Integration tests, uses development DB
 *
 * Created by demian on 14/06/16.
 */
@Integration
@Rollback
class DomainSpec extends Specification{

    def setup() {
    }

    def cleanup() {

    }

    void "Can we list and load an activation key"() {
        when:
        def keys = WpActivationKey.list()
        def key1 = WpActivationKey.get keys[0].id
        def key2 = WpActivationKey.findByActivationKey keys[0].activationKey

        then:
        keys.size() > 0
        key1 == key2

    }

    void "Can we list and load a company"() {
        when:
        def companies = Company.list()
        def company1 = Company.get companies[0].id
        def company2 = Company.findByName companies[0].name

        then:
        companies.size() > 0
        company1 == company2
    }

    void "Can we list and load a project"() {
        when:
        def projects = Project.list()

        then:
        projects.size() > 0
    }
}

I ran into a few stumbling blocks, all easily overcome
In my case the auto timestamping did not work out the box (as column names where different), but that was incredibly easy to fix.

Here is my Domain Class snippet
 Date dateCreated
 Long projectId

 static mapping = {
  version false
 }

 static constraints = {
  activationKey maxSize: 100, unique: true
        dateCreated column: 'created_date'
 }

I started getting this error
Caused by: java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp
This is because that is a valid SQL date but not in Gorm, this was fixed by appending the following to application.yml datasource:url: connection string
?zeroDateTimeBehavior=convertToNull