Nested Resource Issues in Grails

I'm having trouble understanding how Grails Restful controllers work. I am trying to make a request by mail (see below) to the attached resource. I'm not sure I understand what I need to change to make this work, since it seems that GET requests are building a Bid association with its parent Item element, but when I try to execute POST, I warn that the element cannot be empty.

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 Mapping

 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 

Mail 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 } 

Answer

 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"}]} 
+6
source share
3 answers

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; } 

Other default controller actions will probably not work properly when using sub-URLs. You can also override queryForResource and index if you want to return only bids that refer to an element 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) } 
+1
source

The RestfulController implementation has a getObjectToBind() method that returns a request object. I would suggest overriding this method and returning the map containing the itemId key, as described in the commentary on this method.

Another alternative might be to send itemId to the json http body. This is a bit redundant because the information is already provided in the url. But as a workaround, this could also be a good solution.

0
source

I recommend annotating domain classes with @Resource, even if you are implementing your own controller. The Grails documentation seems to indicate that you are doing this or that, annotating the domain, or writing your own controller, extending the RestfulContoroller.

I found that without annotating the domain class, the request object was not properly bound in the createResource () method. All properties were empty. As soon as I added that the binding to the domain annotation happened as I expected.

In your case, I expect / hope that Grails will handle all relationships without requiring you to independently manage the element identifier. So,

 @Resource(uri='items') class Item { static hasMany = [bids:Bid] } 

and...

 @Resource(uri='bids') class Bid { Integer ownerId Double amount static belongsTo = [item:Item] static constraints = { ownerId nullable: false amount nullable: false } } 

I hope you no longer need to override getObjectToBind ().

 class BidController extends RestfulController<Bid> { static responseFormats = ['json', 'xml'] BidController() { super(Bid) } //don't override the getObjectTobind } 

This worked for me when I tried to send an object with a one-to-one mapping to another object.

0
source

Source: https://habr.com/ru/post/972849/


All Articles