Discussion:
Nested RESTful Ressources
sezer.yilmaz
2014-02-21 23:07:08 UTC
Permalink
Hi everyone,

since a couple of days I am evaluating some frameworks for building a
REST-Backend and I really like Grails. Now I've got the following Problem
for which I couldn't find a solution anywhere.

class UrlMappings {

...

"/api/v1/authors"(resources:"Author") {
"/books"(resources:"Book")
}

...

}

@Resource(formats=['json', 'xml'])
class Author {

String name

static hasMany = [books: Book]

static constraints = {
}
}

@Resource(formats=['json', 'xml'])
class Book {

String title;
String language;

static belongsTo = [author: Author]

static constraints = {
}
}

class BootStrap {

def init = { servletContext ->

def author1 = new Author(name: "Goethe").save(failOnError: true)
def author2 = new Author(name: "Kafka").save(failOnError: true)

def book1 = new Book(title: "Bla Bla Book 1", language: "German",
author: author1).save(failOnError: true)
def book2 = new Book(title: "Blah Book 2", language: "German",
author: author1).save(failOnError: true)
def book3 = new Book(title: "Blaaah Book 3", language: "German",
author: author1).save(failOnError: true)

}
def destroy = {
}
}

This is all I have, really simple. Thanks to the scaffolding etc. i get the
following result when I call

http://localhost:8080/GrailsTest/api/v1/authors/1/books ->

[
{
class: "grailstest.Book",
id: 1,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Bla Bla Book 1"
},
{
class: "grailstest.Book",
id: 2,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blah Book 2"
},
{
class: "grailstest.Book",
id: 3,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blaaah Book 3"
}
]

Really really cool that this works with just a couple of lines of code.
BUT HERE'S MY PROBLEM:

When I call the books of the second author which really has no books I get
again all the books in the database.

http://localhost:8080/GrailsTest/api/v1/authors/2/books ->

[
{
class: "grailstest.Book",
id: 1,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Bla Bla Book 1"
},
{
class: "grailstest.Book",
id: 2,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blah Book 2"
},
{
class: "grailstest.Book",
id: 3,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blaaah Book 3"
}
]

What am I doing wrong ? Would be nice if someone could point me to the right
direction.
Thanks





--
View this message in context: http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317.html
Sent from the Grails - user mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Daniel Woods
2014-02-21 23:09:03 UTC
Permalink
What version of Grails?
Post by sezer.yilmaz
Hi everyone,
since a couple of days I am evaluating some frameworks for building a
REST-Backend and I really like Grails. Now I've got the following Problem
for which I couldn't find a solution anywhere.
class UrlMappings {
...
"/api/v1/authors"(resources:"Author") {
"/books"(resources:"Book")
}
...
}
@Resource(formats=['json', 'xml'])
class Author {
String name
static hasMany = [books: Book]
static constraints = {
}
}
@Resource(formats=['json', 'xml'])
class Book {
String title;
String language;
static belongsTo = [author: Author]
static constraints = {
}
}
class BootStrap {
def init = { servletContext ->
def author1 = new Author(name: "Goethe").save(failOnError: true)
def author2 = new Author(name: "Kafka").save(failOnError: true)
def book1 = new Book(title: "Bla Bla Book 1", language: "German",
author: author1).save(failOnError: true)
def book2 = new Book(title: "Blah Book 2", language: "German",
author: author1).save(failOnError: true)
def book3 = new Book(title: "Blaaah Book 3", language: "German",
author: author1).save(failOnError: true)
}
def destroy = {
}
}
This is all I have, really simple. Thanks to the scaffolding etc. i get the
following result when I call
http://localhost:8080/GrailsTest/api/v1/authors/1/books ->
[
{
class: "grailstest.Book",
id: 1,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Bla Bla Book 1"
},
{
class: "grailstest.Book",
id: 2,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blah Book 2"
},
{
class: "grailstest.Book",
id: 3,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blaaah Book 3"
}
]
Really really cool that this works with just a couple of lines of code.
When I call the books of the second author which really has no books I get
again all the books in the database.
http://localhost:8080/GrailsTest/api/v1/authors/2/books ->
[
{
class: "grailstest.Book",
id: 1,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Bla Bla Book 1"
},
{
class: "grailstest.Book",
id: 2,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blah Book 2"
},
{
class: "grailstest.Book",
id: 3,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blaaah Book 3"
}
]
What am I doing wrong ? Would be nice if someone could point me to the right
direction.
Thanks
--
http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317.html
Sent from the Grails - user mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
sezer.yilmaz
2014-02-21 23:22:22 UTC
Permalink
Hi Daniel,

I'm using Grails 2.3.6 with jdk1.7.0_45 on Windows.

Thanks



--
View this message in context: http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4654320.html
Sent from the Grails - user mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Owen Rubel
2014-02-22 00:19:09 UTC
Permalink
Have you tried the api toolkit? It doesnt rely on the domains, it relys on
returned datasets; so you can return data from domains, mixed domains,
files, calculations etc. It also adds in functionality for apidoc
generation, webhooks and api chaining. http://grails.org/plugin/api-toolkit

Owen Rubel
415-971-0976
Post by sezer.yilmaz
Hi everyone,
since a couple of days I am evaluating some frameworks for building a
REST-Backend and I really like Grails. Now I've got the following Problem
for which I couldn't find a solution anywhere.
class UrlMappings {
...
"/api/v1/authors"(resources:"Author") {
"/books"(resources:"Book")
}
...
}
@Resource(formats=['json', 'xml'])
class Author {
String name
static hasMany = [books: Book]
static constraints = {
}
}
@Resource(formats=['json', 'xml'])
class Book {
String title;
String language;
static belongsTo = [author: Author]
static constraints = {
}
}
class BootStrap {
def init = { servletContext ->
def author1 = new Author(name: "Goethe").save(failOnError: true)
def author2 = new Author(name: "Kafka").save(failOnError: true)
def book1 = new Book(title: "Bla Bla Book 1", language: "German",
author: author1).save(failOnError: true)
def book2 = new Book(title: "Blah Book 2", language: "German",
author: author1).save(failOnError: true)
def book3 = new Book(title: "Blaaah Book 3", language: "German",
author: author1).save(failOnError: true)
}
def destroy = {
}
}
This is all I have, really simple. Thanks to the scaffolding etc. i get the
following result when I call
http://localhost:8080/GrailsTest/api/v1/authors/1/books ->
[
{
class: "grailstest.Book",
id: 1,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Bla Bla Book 1"
},
{
class: "grailstest.Book",
id: 2,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blah Book 2"
},
{
class: "grailstest.Book",
id: 3,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blaaah Book 3"
}
]
Really really cool that this works with just a couple of lines of code.
When I call the books of the second author which really has no books I get
again all the books in the database.
http://localhost:8080/GrailsTest/api/v1/authors/2/books ->
[
{
class: "grailstest.Book",
id: 1,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Bla Bla Book 1"
},
{
class: "grailstest.Book",
id: 2,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blah Book 2"
},
{
class: "grailstest.Book",
id: 3,
author: {
class: "Author",
id: 1
},
language: "German",
title: "Blaaah Book 3"
}
]
What am I doing wrong ? Would be nice if someone could point me to the right
direction.
Thanks
--
http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317.html
Sent from the Grails - user mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
sezer.yilmaz
2014-02-22 00:34:51 UTC
Permalink
Thank you Owen, sounds promising, I will definitely have a look at it.

So is the described behaviour a Bug or am I doing something wrong ?
How do achieve the desired behaviour, showing only the Books of a certain
Author, without using plugins ?



--
View this message in context: http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4654323.html
Sent from the Grails - user mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Owen Rubel
2014-02-22 01:08:27 UTC
Permalink
I'm perhaps the wrong person to ask. In theory it should be able to handle
data sets as well as objects. What kind of error are you getting?

Owen Rubel
415-971-0976
Post by sezer.yilmaz
Thank you Owen, sounds promising, I will definitely have a look at it.
So is the described behaviour a Bug or am I doing something wrong ?
How do achieve the desired behaviour, showing only the Books of a certain
Author, without using plugins ?
--
http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4654323.html
Sent from the Grails - user mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
sezer.yilmaz
2014-02-22 11:25:11 UTC
Permalink
Ok maybe I should be more precise. My nested URL mapping is as follows

"/api/v1/authors"(resources:"Author") {
"/books"(resources:"Book")
}

resulting in the following examplified URL

http://localhost:8080/GrailsTest/api/v1/authors/2/books

Now the expected behaviour would be that I only get the books of the author
with ID 2,
but no matter which author you take, you always get all existing books in
the database.
The books are not filtered by author as one would expect by the nested
mapping above.

I still couldn't find a solution. Maybe I'm expecting too much from Grails.

Anyone ?





--
View this message in context: http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4654335.html
Sent from the Grails - user mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Owen Rubel
2014-02-22 16:35:53 UTC
Permalink
Its not too much for grails, just try a different approach. The api toolkit
was built to handle datasets rather than GORM objects. As such, you can
return any dataset you wish and it will handle it; build the query in the
method and return the data... just that simple.

Owen Rubel
415-971-0976
Post by sezer.yilmaz
Ok maybe I should be more precise. My nested URL mapping is as follows
"/api/v1/authors"(resources:"Author") {
"/books"(resources:"Book")
}
resulting in the following examplified URL
http://localhost:8080/GrailsTest/api/v1/authors/2/books
Now the expected behaviour would be that I only get the books of the author
with ID 2,
but no matter which author you take, you always get all existing books in
the database.
The books are not filtered by author as one would expect by the nested
mapping above.
I still couldn't find a solution. Maybe I'm expecting too much from Grails.
Anyone ?
--
http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4654335.html
Sent from the Grails - user mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
Eamonn O'Connell
2014-02-22 18:08:17 UTC
Permalink
You might need to look at implementing your own controllers. The
inheritance strategy in the docs even comes with an example of what you are
looking for.
Post by Owen Rubel
Its not too much for grails, just try a different approach. The api
toolkit was built to handle datasets rather than GORM objects. As such, you
can return any dataset you wish and it will handle it; build the query in
the method and return the data... just that simple.
Owen Rubel
415-971-0976
Post by sezer.yilmaz
Ok maybe I should be more precise. My nested URL mapping is as follows
"/api/v1/authors"(resources:"Author") {
"/books"(resources:"Book")
}
resulting in the following examplified URL
http://localhost:8080/GrailsTest/api/v1/authors/2/books
Now the expected behaviour would be that I only get the books of the author
with ID 2,
but no matter which author you take, you always get all existing books in
the database.
The books are not filtered by author as one would expect by the nested
mapping above.
I still couldn't find a solution. Maybe I'm expecting too much from Grails.
Anyone ?
--
http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4654335.html
Sent from the Grails - user mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
sezer.yilmaz
2014-02-22 18:50:23 UTC
Permalink
Ok, I assumed that the dynamically scaffolded controllers would implement
some sort of inheritance dependent on the URL mapping. So this is not how
things work, but sooner or later I would have needed to implement my own
controllers anyway.

I think I should write my own static scaffolding templates for the
controllers, thanks for the hint Eamonn !

A theoretical question just out of curiosity..is it also possible to
customize dynamic scaffolding ?

Thank you all for your help



--
View this message in context: http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4654345.html
Sent from the Grails - user mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Paolo Piersanti
2014-02-26 08:32:01 UTC
Permalink
Post by sezer.yilmaz
A theoretical question just out of curiosity..is it also possible to
customize dynamic scaffolding ?
Take a look at
http://grails.org/doc/2.3.x/ref/Command%20Line/install-templates.html

Paolo
--
Signature for Rent - Questo spazio si affitta
Paolo Piersanti Software Developer & System Admininistrator
Graeme Rocher
2014-02-27 08:34:12 UTC
Permalink
The scaffolding doesn't automatically scope your REST calls, you need
to subclass RestfulController and provide an implementation that
includes the authorId. There is an example in the documentation:

http://grails.org/doc/latest/guide/webServices.html#extendingRestfulController

Cheers
Post by sezer.yilmaz
Ok, I assumed that the dynamically scaffolded controllers would implement
some sort of inheritance dependent on the URL mapping. So this is not how
things work, but sooner or later I would have needed to implement my own
controllers anyway.
I think I should write my own static scaffolding templates for the
controllers, thanks for the hint Eamonn !
A theoretical question just out of curiosity..is it also possible to
customize dynamic scaffolding ?
Thank you all for your help
--
View this message in context: http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4654345.html
Sent from the Grails - user mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
--
Graeme Rocher
Grails Project Lead
SpringSource

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
sezer.yilmaz
2014-03-08 18:26:45 UTC
Permalink
Thank you Graeme, your help is much appreciated. Finally I got it. I didn't
have a lot of time in the last couple of days because of exams in university
but I gave it a try again today and was quite succesful.

The example in the doc you are referring to is probably

@Override
Book queryForResource(Serializable id) {
Book.where {
id == id && author.id = params.authorId
}.find()
}

The first Problem I got is that this results in a couple of compile errors
and warnings.
Someone already reported this here:
http://jira.grails.org/browse/GRAILS-11083
I also think that overriding the listAllResources Method could be more
appropriate because we're talking about a One-To-Many Relationship.

So here's my solution, maybe it will be helpful for someone:

In the Book Controller:

@Override
Book queryForResource(Serializable id) {
Book.get(id)
}

@Override
List<Book> listAllResources(Map params) {
def author = Author.findById(params.AuthorId)
if(author){
Book.findAllByAuthor(author)
} else {
Book.list()
}
}

In the Author Controller:
@Override
Author queryForResource(Serializable id) {
def book = Book.findById(params.BookId)

if(book){
book.author
} else {
Author.get(id)
}

}

@Override
List<Author> listAllResources(Map params) {
def author = Author.findById(params.AuthorId)
if(author){
Book.findAllByAuthor(author)
} else {
Book.list()
}
}

I'm so happy it works now..

http://localhost:8080/GrailsTest/api/v1/authors/2/books results in only the
books of the Author with ID 2 now.

Let's try the other way arround.
I also defined the following the mapping:

"/api/v1/books"(resources:"Book", version:'1.0', namespace:'v1') {
"/author"(resource:"Author", version:'1.0', namespace:'v1')
}

So I should be able to do something like this:
http://localhost:8080/GrailsTest/api/v1/books/1/author

This should give me the author of a certain book, BUT unfortunately I get:
405: specified HTTP method is not allowed for the requested resource

This should not be true because the really helpful url-mapping-report tells
me correctly:

Controller: Author
...
| POST | /api/v1/books/${BookId}/author | Action: save
| GET | /api/v1/books/${BookId}/author | Action: show
| PUT | /api/v1/books/${BookId}/author | Action: update
| DELETE | /api/v1/books/${BookId}/author | Action: delete
...

I'm trying to solve this issue for a couple of hours now, I don't get it.
I also print debug messages when the controller is called with

def beforeInterceptor = {
println "Entering Action ${actionUri}"
println params
}

This code is never reached when I call the above URL.
When I just call http://localhost:8080/GrailsTest/api/v1/books/1 everything
works correct and the console output is as follows:

Entering Action /book/show
[id:1, action:delete, controller:Book]

Why the 405 ? Could someone please help me ?

@gon: Thanks for the hint with install-templates. Isn't that only for static
scaffolding/code generation ? These templates are not used by the dynamic
scaffolding. It seems that dynamic scaffolding is not customizable in
Grails, please correct me if I'm wrong Graeme ?





--
View this message in context: http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4654841.html
Sent from the Grails - user mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
sezer.yilmaz
2014-05-28 22:25:45 UTC
Permalink
Hi,

I provided a fix for this which should be available in the newer releases of
grails.
Here's the jira issue for reference:
https://jira.grails.org/plugins/servlet/mobile#issue/GRAILS-11211

Cheers



--
View this message in context: http://grails.1312388.n4.nabble.com/Nested-RESTful-Ressources-tp4654317p4657037.html
Sent from the Grails - user mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Loading...