I'm having issues understanding how Grails Restful controllers work. I'm attempting to make a post request (see below) to a nested resource. I'm not sure I understand what I need to change to make this work, as it seems that GET requests build the Bid's association with it's parent resource Item, but when I attempt to POST I am warned that the Item cannot be blank.
Any help is appreciated!
Item.groovy
class Item {
static hasMany = [bids:Bid]
}
Bid.groovy
class Bid {
Integer ownerId
Double amount
static belongsTo = [item:Item]
static constraints = {
ownerId nullable: false
amount nullable: false
}
}
BidController.groovy
class BidController extends RestfulController<Bid> {
static responseFormats = ['json', 'xml']
BidController() {
super(Bid)
}
@Override
def getObjectToBind() {
request.parameterMap.put('itemId', params.itemId)
return request
}
}
ItemController.groovy
class ItemController extends RestfulController<Item> {
static responseFormats = ['json', 'xml']
ItemController() {
super(Item)
}
}
UrlMappings.groovy
class UrlMappings {
static mappings = {
"/items"(resources:"item") {
"/bids"(resources: "bid")
}
}
}
URL Mappings
Controller: item
| GET | /items | Action: index
| GET | /items/create | Action: create
| POST | /items | Action: save
| GET | /items/${id} | Action: show
| GET | /items/${id}/edit | Action: edit
| PUT | /items/${id} | Action: update
| PATCH | /items/${id} | Action: patch
| DELETE | /items/${id} | Action: delete
Controller: bid
| GET | /items/${itemId}/bids | Action: index
| GET | /items/${itemId}/bids/create | Action: create
| POST | /items/${itemId}/bids | Action: save
| GET | /items/${itemId}/bids/${id} | Action: show
| GET | /items/${itemId}/bids/${id}/edit | Action: edit
| PUT | /items/${itemId}/bids/${id} | Action: update
| PATCH | /items/${itemId}/bids/${id} | Action: patch
| DELETE | /items/${itemId}/bids/${id} | Action: delete
Post Request
POST /AuctionService/items/1/bids HTTP/1.1
Content-Type: application/json
Host: localhost:8080
Connection: close
Content-Length: 34
{
"ownerId": 1,
"amount": 3.00
}
Response
HTTP/1.1 422 Unprocessable Entity
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 25 Jul 2014 17:44:03 GMT
Connection: close
{"errors":[{"object":"auctionservice.Bid","field":"item","rejected-value":null,"message":"Property [item] of class [class auctionservice.Bid] cannot be null"}]}
I think you can accomplish what you want by overriding the createResource() method.
@Override
protected Bid createResource() {
Bid bid=super.createResource();
bid.item=Item.get(params.itemId)
return bid;
}
The other default controller actions will probably not work as expected when using nested URLs. You may also want to override queryForResource and index if you want to ensure that you only return Bids that belong to the item in the URL
@Override
protected Stay queryForResource(Serializable id) {
def itemId=params.itemId
Bid.where {
id==id && item.id == itemId
}.find()
}
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
def itemId=params.itemId
respond Bid.where {
item.id==itemId
}.list(params)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With