Adding functionality to Grails restfulcontroller - rest

I'm having a very simple restful controller, which looks like this:
class PersonController extends RestfulController<Person> {
static responseFormats = ['json', 'xml']
PersonController() {
super(Person)
}
}
However, now I want to add a search option to this. What is the Grails way of making this possible?
I thought of adding the following:
def search(Map params) {
println params
}
But that makes Grails (2.3) crash (| Error Fatal error during compilation org.apache.tools.ant.BuildException: Compilation Failed (Use --stacktrace to see the full trace)).
So what is the right way of adding this? I'm looking for some solution which I can call using http://localhost:8080/foo/person/search?q=erik
This is my UrlMappings:
static mappings = {
"/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
"/rest/persons"(resources:'Person')
I've changed the above to:
def search() {
println params
}
And that doesn't give the compilation error anymore, but I still get this error:
TypeMismatchException occurred when processing request: [GET] /declaratie-web/rest/medicaties/search - parameters:
q: erik
Provided id of the wrong type for class nl.Person. Expected: class java.lang.Long, got class java.lang.String. Stacktrace follows:
org.hibernate.TypeMismatchException: Provided id of the wrong type for class nl.Person. Expected: class java.lang.Long, got class java.lang.String
I also found out that it doesn't matter how I call the controller:
http://localhost:8080/foo/person/search?q=erik
http://localhost:8080/foo/person/search222?q=erik
http://localhost:8080/foo/person/search39839329?q=erik
All fails with the above error, so it seems my method is ignored (maybe caused by my URLmapping?)

You really aren't being RESTful by doing that. q should just be a parameter for the index action. You can override that method to include your functionality.
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
def c = Person.createCriteria()
def results = c.list(params) {
//Your criteria here with params.q
}
respond results, model:[personCount: results.totalCount]
}

#james-kleeh solution is right, but you can do it more clean by override the listAllResources method which is called by index
#Override
protected List<Payment> listAllResources(Map params) {
Person.createCriteria().list(params) {
// Your criteria here with params.q
}
}

Related

How to define a class that is exactly the same as another class in Dart/Flutter

I'm defining some custom Exceptions in Dart.
I want in my logic to check the type of exception and base my processing on that, so I want to create distinct classes for each, for example like this :
class FailedToLoadCriticalDataException implements Exception { } // app cannot continue
class FailedToLoadNonCriticalDataException implements Exception { } // app can continue
However I also want to pass 2 parameters when I create these types of exceptions, the type of API call, and the API url, and the definition for that would look like this :
class UrlCallFailedException implements Exception {
String _dataTypeName;
String _urlEndpoint;
UrlCallFailedException([this._dataTypeName, this._urlEndpoint]);
#override
String toString() {
return "(${this.runtimeType.toString()}) Failed to fetch $_dataTypeName ($_urlEndpoint)";
}
}
Now what I want to do is (replace the initial definitions I made earlier and re)define my FailedToLoadCriticalDataException and FailedToLoadNonCriticalDataException classes so that they are exactly the code that is in the UrlCallFailedException class.
Is there any way to simply say something like class FailedToLoadCriticalDataException **is** UrlCallFailedException; and not need to duplicate the code that defines UrlCallFailedException ?
class FailedToLoadCriticalDataException implements UrlCallFailedException{ } is wrong because it is "Missing concrete implementations of 'getter UrlCallFailedException._dataTypeName',.."
class FailedToLoadCriticalDataException extends UrlCallFailedException{ } is wrong because when I got to throw FailedToLoadNonCriticalDataException("Foo", url); it's expectation is that there are no params ("Too many positional arguments: 0 expected, but 2 found.").
Is there a way to create multiple classes that behave exactly the same as another type and differ only in their class, without duplicating all the code ?
I've come up with this as a decent compromise :
class FailedToLoadCriticalDataException extends UrlCallFailedException {
FailedToLoadCriticalDataException([dataTypeName, urlEndpoint]) {
super._dataTypeName = dataTypeName;
super._urlEndpoint = urlEndpoint;
}
}
class FailedToLoadNonCriticalDataException extends UrlCallFailedException {
FailedToLoadNonCriticalDataException([dataTypeName, urlEndpoint]) {
super._dataTypeName = dataTypeName;
super._urlEndpoint = urlEndpoint;
}
}
Some, but minimal, code duplication, and I can now call throw FailedToLoadNonCriticalDataException("Foo", url); in my code later.

How can I log a warning when I "halt()" in Scalatra?

In my Scalatra routes, I often use halt() to fail fast:
val user: User = userRepository.getUserById(params("userId"))
.getOrElse {
logger.warn(s"Unknown user: $userId")
halt(404, s"Unknown user: $userId")
}
As shown in the example, I also want to log a warning in those cases. But I'd like to avoid the code duplication between the halt() and the logger. It would be a lot cleaner to simply do:
val user: User = userRepository.getUserById(params("userId"))
.getOrElse(halt(404, s"Unknown user: $userId"))
What would be the best way of logging all "HaltExceptions" in a cross-cutting manner ?
I've considered:
1) Overriding the halt() method in my route:
override def halt[T](status: Integer, body: T, headers: Map[String, String])(implicit evidence$1: Manifest[T]): Nothing = {
logger.warn(s"Halting with status $status and message: $body")
super.halt(status, body, headers)
}
Aside from the weird method signature, I don't really like this approach, because I could be calling the real halt() by mistake instead of the overridden method, for example if I'm halting outside the route. In this case, no warning would be logged.
2) Use trap() to log all error responses:
trap(400 to 600) {
logger.warn(s"Error returned with status $status and body ${extractBodyInSomeWay()}")
}
But I'm not sure it's the best approach, especially since it adds 201 routes to the _statusRoutes Map (one mapping for each integer in the range...). I also don't know how to extract the body here ?
3) Enable some kind of response logging in Jetty for specific status codes ?
What would be the best approach to do this? Am I even approaching this correctly?
The easiest solution is doing it in a servlet filter like below:
package org.scalatra.example
import javax.servlet._
import javax.servlet.http.HttpServletResponse
class LoggingFilter extends Filter {
override def init(filterConfig: FilterConfig): Unit = ()
override def destroy(): Unit = ()
override def doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain): Unit = {
chain.doFilter(request, response)
val status = response.asInstanceOf[HttpServletResponse].getStatus
if (status >= 400 && status <= 600) {
// Do logging here!
}
}
}
Register this filter in your Bootstrap class (or it's possible even in web.xml):
package org.scalatra.example
import org.scalatra._
import javax.servlet.ServletContext
class ScalatraBootstrap extends LifeCycle {
override def init(context: ServletContext): Unit = {
context.addFilter("loggingFilter", new LoggingFilter())
context.getFilterRegistration("loggingFilter")
.addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/*")
// mount your servlets or filters
...
}
}
In my opinion, Scalatra should provide a way to trap halting easier essentially. In fact, there is a method named renderHaltException in ScalatraBase, it looks to be possible to add logging by overriding this method at a glance:
https://github.com/scalatra/scalatra/blob/cec3f75e3484f2233274b1af900f078eb15c35b1/core/src/main/scala/org/scalatra/ScalatraBase.scala#L512
However we can't do it actually because HaltException is package private and it can be accessed inside of org.scalatra package only. I wonder HaltException should be public.

How to properly bind current object context in ES6 using babelify

I'm trying to bind current instance to the class method, please note ES6 syntax.
class SomeClass {
search() => { ... }
}
Which is 100% legit code, however, babelify doesn't want to compile it
SyntaxError: /Users/vladmiller/Projects/test/test/client/test/app/pages/Search.react.js: Unexpected token (50:26) while parsing file: /Users/vladmiller/Projects/test/test/client/test/app/pages/Search.react.js\
Instead, now I have to bind context in class constructor
class SomeClass {
constructor() {
this.search = this.search.bind(this)
}
search() { ... }
}
Which is quite annoying and boring.
UPD: It turns out that this is invalid ES6 syntax; therefore the question is follows. What is the best way to bind instance context to a class method?
UPD2: By default context should be attached, however, the issue with React http://jsbin.com/citafaradu/2/edit?js,console,output
This code is not valid ES2015. Prototype methods are defined like this:
class SomeClass {
search() { /* ... */ }
}

Why can't I instantiate a Groovy class from another Groovy class?

I have two classes. One.groovy:
class One {
One() {}
def someMethod(String hey) {
println(hey)
}
}
And Two.groovy:
class Two {
def one
Two() {
Class groovy = ((GroovyClassLoader) this.class.classLoader).parseClass("One.groovy")
one = groovy.newInstance()
one.someMethod("Yo!")
}
}
I instantiate Two with something like this:
GroovyClassLoader gcl = new GroovyClassLoader();
Class cl = gcl.parseClass(new File("Two.groovy"));
Object instance = cl.newInstance();
But now I get groovy.lang.MissingMethodException: No signature of method: script13561062248721121730020.someMethod() is applicable for argument types: (java.lang.String) values: [Yo!]
Any ideas?
Seems like it is occurring due to the groovy class loader method being called: the string one is to parse a script in text format. Using the File one worked here:
class Two {
def one
Two() {
Class groovy = ((GroovyClassLoader) this.class.classLoader).parseClass("One.groovy")
assert groovy.superclass == Script // whoops, not what we wanted
Class groovy2 = ((GroovyClassLoader) this.class.classLoader).parseClass(new File("One.groovy"))
one = groovy2.newInstance()
assert one.class == One // now we are talking :-)
one.someMethod("Yo!") // prints fine
}
}

Grails new domain instance returns null

I have a domain class that looks like this:
class Offerbyuser {
Number offerPrice
Number minHours
static constraints = {}
}
Then in a controller, I do this:
def offer = new Offerbyuser(offerPrice:1, minHours:3)
offer is always NULL. Why? Am I missing something obvious?
UPDATE: so this DOES work, but what's not working I found out is the method after that.
user.addToOutgoingOffers(offer)
user has a one-to-many relationship with Offerbyuser domain class:
class User {
static hasMany = [outgoingOffers:Offerbyuser]
}
I get this error:
groovy.lang.MissingMethodException: No signature of method: twitter4j.UserJSONImpl.addToOutgoingOffers() is applicable for argument types: (test.Offerbyuser) values: [Offer by user - Price: 1, Tweet hours: 3]
Your code works fine for me. I think that it maybe your controller class is not in the same package with your domain class, and you maynot include the domain class. Grails can not find the class you "new", but since Groovy is a dynamic language it won't throw an error.
Please try this:
In domain class
package test
class Offerbyuser {
...
}
In controller:
package test
class TestController {
...
def doSomething = {
def offer = new Offerbyuser(offerPrice:1, minHours:5)
}
}