Skip to content

Instantly share code, notes, and snippets.

@mnellemann
Last active June 23, 2016 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mnellemann/7cfff1c721ef32f0be6c63574795f795 to your computer and use it in GitHub Desktop.
Save mnellemann/7cfff1c721ef32f0be6c63574795f795 to your computer and use it in GitHub Desktop.
Grails 3.1.8 restful controllers, nested resources in UrlMappings
package adb
class Customer {
String id
String name
String notes
static hasMany = [ solutions: Solution ]
static constraints = {
id(bindable: true, unique: true, minSize: 3, maxSize: 8, matches: "[a-zA-Z0-9]+")
name(maxSize: 128)
notes(nullable: true, maxSize: 4096)
}
String toString() {
return id
}
static mapping = {
id generator:'assigned'
}
}
package adb
import grails.plugin.springsecurity.annotation.Secured
import grails.rest.RestfulController
@Secured(['permitAll'])
class RestCustomerController extends RestfulController {
static responseFormats = ['json', 'xml']
RestCustomerController() {
super(Customer)
}
}
package adb
import grails.plugin.springsecurity.annotation.Secured
import grails.rest.RestfulController
@Secured(['permitAll'])
class RestSolutionController extends RestfulController {
static responseFormats = ['json', 'xml']
RestSolutionController() {
super(Solution)
}
}
package adb
class Solution {
String id
String publicURL
String customURL
String customSSL
String notes
static belongsTo = [customer: Customer]
static constraints = {
id(bindable: true, unique: true, minSize: 3, maxSize: 16, matches: "[a-zA-Z0-9]+-(stag|prod)")
publicURL(nullable: true, url: true)
customURL(nullable: true)
customSSL(nullable: true)
customer(nullable: true)
notes(nullable: true, maxSize: 4096)
}
static mapping = {
id generator:'assigned'
}
String toString() {
return id
}
}
| * | ERROR: 404 | View: /notFound |
| * | ERROR: 500 | View: /error |
| * | / | Action: (default action) |
| * | /${controller}/${action}?/${id}?(.${format)? | Action: (default action) |
Controller: RestCustomer
| GET | /api/customers/create | Action: create |
| GET | /api/customers/${id}/edit | Action: edit |
| POST | /api/customers | Action: save |
| GET | /api/customers | Action: index |
| DELETE | /api/customers/${id} | Action: delete |
| PATCH | /api/customers/${id} | Action: patch |
| PUT | /api/customers/${id} | Action: update |
| GET | /api/customers/${id} | Action: show |
Controller: RestSolution
| GET | /api/customers/${RestCustomerId}/solutions/create | Action: create |
| GET | /api/customers/${RestCustomerId}/solutions/${id}/edit | Action: edit |
| POST | /api/customers/${RestCustomerId}/solutions | Action: save |
| GET | /api/customers/${RestCustomerId}/solutions | Action: index |
| DELETE | /api/customers/${RestCustomerId}/solutions/${id} | Action: delete |
| PATCH | /api/customers/${RestCustomerId}/solutions/${id} | Action: patch |
| PUT | /api/customers/${RestCustomerId}/solutions/${id} | Action: update |
| GET | /api/customers/${RestCustomerId}/solutions/${id} | Action: show |
package adb
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
// Rest API
group ("/api") {
"/customers"(resources: 'RestCustomer') {
"/solutions"(resources: 'RestSolution')
}
}
"/"(redirect: "/dashboard/index")
"500"(view:'/error')
"404"(view:'/notFound')
}
}
@mnellemann
Copy link
Author

mnellemann commented Jun 23, 2016

Creating some test data

def test = new Customer(name: 'Test Customer', id: 'test').save(failOnError: true)
def test_stag = new Solution(id: 'test-stag', customer: test).save(failOnError: true)
def test_prod = new Solution(id: 'test-prod', customer: test, publicURL: 'https://campaign.test.com').save(failOnError: true)

def demo = new Customer(name: 'Demo Customer', id: 'demo').save(failOnError: true)
def demo_stag = new Solution(id: 'demo-stag', customer: demo).save(failOnError: true)
def demo_prod = new Solution(id: 'demo-prod', customer: demo, publicURL: 'https://campaign.demo.com').save(failOnError: true)

Getting list of customers

$ curl -H "Accept: application/json" http://localhost:8080/api/customers 
[
  {
    "id": "test",
    "name": "Test Customer",
    "notes": null,
    "solutions": [
      {
        "id": "test-stag"
      },
      {
        "id": "test-prod"
      }
    ],
  },
  {
    "id": "demo",
    "name": "Demo Customer",
    "notes": null,
    "solutions": [
      {
        "id": "demo-prod"
      },
      {
        "id": "demo-stag"
      }
    ],
  }
]

I would then expect to be able to list solution for this specific customer, but I get a list of all solutions:

$  curl -H "Accept: application/json"  http://localhost:8080/api/customers/test/solutions
[
  {
    "id": "test-stag",
    "customSSL": null,
    "customURL": null,
    "customer": {
      "id": "test"
    },
    "notes": null,
    "publicURL": null,
  },
  {
    "id": "test-prod",
    "customSSL": null,
    "customURL": null,
    "customer": {
      "id": "test"
    },
    "notes": null,
    "publicURL": "https://campaign.test.com",
  },
  {
    "id": "demo-stag",
    "customSSL": null,
    "customURL": null,
    "customer": {
      "id": "demo"
    },
    "integrationSas": false,
    "notes": null,
    "publicURL": null,
  },
  {
    "id": "demo-prod",
    "customSSL": null,
    "customURL": null,
    "customer": {
      "id": "demo"
    },
    "notes": null,
    "publicURL": "https://campaign.demo.com",
  }
]

When I enter something not-existing for customer-ID, I get the same list of all solutions. I suspect this has to do with my custom assigned ID?

$ curl -H "Accept: application/json" http://localhost:8080/api/customers/blabla/solutions
[
  {
    "id": "test-stag",
    "customSSL": null,
    "customURL": null,
    "customer": {
      "id": "test"
    },
    "notes": null,
    "publicURL": null,
  },
  {
    "id": "test-prod",
    "customSSL": null,
    "customURL": null,
    "customer": {
      "id": "test"
    },
    "notes": null,
    "publicURL": "https://campaign.test.com",
  },
  {
    "id": "demo-stag",
    "customSSL": null,
    "customURL": null,
    "customer": {
      "id": "demo"
    },
    "integrationSas": false,
    "notes": null,
    "publicURL": null,
  },
  {
    "id": "demo-prod",
    "customSSL": null,
    "customURL": null,
    "customer": {
      "id": "demo"
    },
    "notes": null,
    "publicURL": "https://campaign.demo.com",
  }
]

@mnellemann
Copy link
Author

Solved by adding the following to RestSolutionController.groovy:

    @Override
    protected List<Solution> listAllResources(Map params) {
        Solution.where { customer.id == params.RestCustomerId }.list(params)
    }

But - should it have worked without ?
Or not return anything compared to returning everything ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment