Grails RESTful API Plugin - wrong service siginiture - rest

I am trying to use Restful API plugin (Restful API plugin). (using Grails 2.3.8, Groovy 2.1)
As stated in documentation I created a Grails service that implements RestfulServiceAdapter.
import net.hedtech.restfulapi.RestfulServiceAdapter
import com.game.trivia.Question
#Transactional
class QuestionService implements RestfulServiceAdapter {
#Override
public Object list(def service, Map params) throws Throwable{
List Q = Question.list(params)
return Q;
}
.
.
.
When trying to access the service: http://localhost:8080/test_triv/api/questions
I received following exception:
{"errors":[{"type":"general",
"errorMessage":"No signature of method: test_triv.QuestionService.list() is applicable for argument types:
(org.codehaus.groovy.grails.web.servlet.mvc.GrailsParameterMap) values:
[[pluralizedResourceName:questions, action:[...], ...]]\nPossible solutions: list(java.lang.Object, java.util.Map),
is(java.lang.Object), wait(), find(), wait(long), with(groovy.lang.Closure)"}]}
So I implemented another list method (which is not part of the interface):
public Object list(Map params) throws Throwable {
List Q = Question.list(params)
return Q;
}
Which works ok.
Am I doing something wrong?
Do I implement the correct interface?
Do I have to expose a service for each domain or there is any way to use an existing controller instead of a service?
Creating new service is a big overhead! I already have controllers for all domains.

Just got reply on this issue from Charlie (The pludin developer):
Our documentation should be clearer in this area, so I'll take an action to look at improving it.
You should not implement the RestfulServiceAdapter within a service, but implement and register an adapter that implements this interface if you need to adapt an existing service that does not provide the expected methods.
Since you are writing a new service, you can just expose the required methods (you don't need to implement any interface). Note the contract is essentially the same as the adapter interface, without the 'service' argument that represents the service to which the adapter would delegate.
To avoid needing an adapter, a service should expose these methods:
def list( Map params ) throws Throwable { ... }
def count( Map params ) throws Throwable { ... }
def show( Map params ) throws Throwable { ... }
def create( Map content, Map params ) throws Throwable { ... }
def update( def id, Map content, Map params ) throws Throwable { ... }
void delete( def id, Map content, Map params ) throws Throwable { ... }
The controller is intended to delegate to a service that contains business logic, and it cannot delegate to another controller. Our expectation is the RestfulApiController and other controllers within an application would share services (e.g., a ThingController and the RESTfulApiController could both use the same ThingService so that business logic is not duplicated).

Related

Call not propagating to the service method from Spring Reactive Controller

I am a beginner to the spring webflux. We are currently migrating our application to Spring Webflux. No I have stuck with a problem. The following is my scenario.
The main service class is calling the following service classes for data
StudentService - return Mono<Student>
StaffService - return Mono<Staff>
Here I have a wrapper class StudentWithMentor to store the result from these service classes.
public class StudentWithMentor {
private Student student;
private Staff mentor;
}
Now in controller I am calling the above 2 services and map it into 'StudentWithMentor' in the following way
Mono<StudentWithMentor> studentWithMentorMono = Mono.just(new StudentWithMentor());
return studentWithMentorMono.map(s->{
studentService.getStudentById(id)
.doOnSuccess(s::setStudent)
.doOnSuccess(st->staffService.getStaffByGrade(st.getGrade()));
return s;
});
But when I call this endpoint I am getting the following result in postman
{
"student": null,
"mentor": null
}
Note: I am getting result from the underlying services when I debugg. But the call is returning before it process.
How can I achieve this in a complete non-blocking way.
Appreciates any help.
The easiest way will be to to use a zipWith operator to merge the results into StudentWithMentor object.
See the code below:
Mono<StudentWithMentor> studentWithMentorMono = studentService.getStudentById(id)
.zipWhen(student -> staffService.getStaffByGrade(student.getGrade()), StudentWithMentor::new);

Create test for rest post method using mock object

i have post method in rest controller and i want to create a test for this method:
This is my method:
#PostMapping("/persons")
public ResponseEntity<PersonDto> createPerson(#RequestBody PersonDto personDto) {
try {
personService.createPerson(personDto);
return ResponseEntity.ok(personDto);
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
I have no idea how this test with mock should look like.
As you use Spring, I recommend you to use #WebMvcTest to mock all things but the Controller under test.
You should so explicitly mock the dependencies of this Controller. In your case, mocking the personService field is enough.
In your test class declare a personService field annotated with #MockBean to create a Mockito mock of the class that will be added to the Spring context.
Then record a behavior for this mock.
You have two branches here : it works and an exception is risen.
So you could define two test method and record a specific behavior in each one.
At last assert the gotten response from the controller.
I already have test for deleting method. Yes i use springboot, jpa, rest, h2:
#Test
public void shouldDeletePersonById() throws Exception {
Mockito.doCallRealMethod().when(personService).deleteById(1L);
mockMvc.perform(delete("/persons/{id}", 1L)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
}
But for create person this looks for me very hard. I don't know what i should call of in posy method(like in delete i call id to find what i want to delete).

Grails 3 Restful Link Generator (w/o the action)

Is there a way to reconfigure the Grails 3 Link Generator to create Restful links, i.e. localhost:8080/book/{id} rather than the old style that includes the action in the URL, localhost:8080/book/show/{id}?
I'd like to have restful URLs in the location headers of the responses to save actions.
I've been using this Grails Restful Link Generator as a workaround. I'm not perfectly happy with it, but it's the best I've been able to come up with thus far.
1. Create a trait in src/main/groovy that removes the superfluous action from the URL
import grails.web.mapping.LinkGenerator
trait RestfulLinkGeneratorTrait {
LinkGenerator grailsLinkGenerator
String generateLink(Map map) {
map.controller = map.controller ?: this.controllerName
map.absolute = map.absolute ?: true
map.action = map.action ?: "show"
grailsLinkGenerator.link(map).replace("/$map.action", "")
}
}
2. Implement the RestfulLinkGenerator on your controller(s) and call generateLink(id: obj.id) to generate links.
#Secured('ROLE_USER')
class BookController extends RestfulController implements RestfulLinkGeneratorTrait {
//... other methods ...//
#Transactional
def save() {
// ... save you resource ... //
response.addHeader(HttpHeaders.LOCATION, generateLink(id: book.id))
respond book, [status: CREATED, view: 'show']
}
//... other methods ...//
}

Scala design suggestion needed

I would like to design a client that would talk to a REST API. I have implemented the bit that actually does call the HTTP methods on the server. I call this Layer, the API layer. Each operation the server exposes is encapsulated as one method in this layer. This method takes as input a ClientContext which contains all the needed information to make the HTTP method call on the server.
I'm now trying to set up the interface to this layer, let's call it ClientLayer. This interface will be the one any users of my client library should use to consume the services. When calling the interface, the user should create the ClientContext, set up the request parameters depending on the operation that he is willing to invoke. With the traditional Java approach, I would have a state on my ClientLayer object which represents the ClientContext:
For example:
public class ClientLayer {
private static final ClientContext;
...
}
I would then have some constructors that would set up my ClientContext. A sample call would look like below:
ClientLayer client = ClientLayer.getDefaultClient();
client.executeMyMethod(client.getClientContext, new MyMethodParameters(...))
Coming to Scala, any suggestions on how to have the same level of simplicity with respect to the ClientContext instantiation while avoiding having it as a state on the ClientLayer?
I would use factory pattern here:
object RestClient {
class ClientContext
class MyMethodParameters
trait Client {
def operation1(params: MyMethodParameters)
}
class MyClient(val context: ClientContext) extends Client {
def operation1(params: MyMethodParameters) = {
// do something here based on the context
}
}
object ClientFactory {
val defaultContext: ClientContext = // set it up here;
def build(context: ClientContext): Client = {
// builder logic here
// object caching can be used to avoid instantiation of duplicate objects
context match {
case _ => new MyClient(context)
}
}
def getDefaultClient = build(defaultContext)
}
def main(args: Array[String]) {
val client = ClientFactory.getDefaultClient
client.operation1(new MyMethodParameters())
}
}

Resteasy (JBoss AS 6) validation

I'm looking for a good pattern of providing custom validation of input for Resteasy services.
Let's say I've this service:
#Local
#Path("/example")
public interface IExample {
public Response doSomething ( #QueryParam("arg1") String arg1, #QueryParam("arg2") Integer arg2);
}
which I've implemented:
#Stateless
public class Example implements IExample {
#Override
public Response doSomething ( String arg1, Integer arg2 ) { ... }
}
What's the best practice to validate arg1 and arg2?
My ideas:
Validate inside doSomething(...) method. Drawback: when I add some parameter (ex. arg3) in the future, I could easily forget to validate it.
In custom javax.servlet.Filter. Drawback: I cannot access arg1 and arg2 there as they're not yet parsed by Resteasy framework.
I came up with this concept:
public class ExampleValidator implements IExample {
public static class ValidationError extends RuntimeException { ... }
#Override
public Response doSomething ( String arg1, Integer arg2 ) {
// here do validation. In case of failure, throw ValidationError
return null;
}
}
which can be used as follows:
#Stateless
public class Example implements IExample {
#Override
public Response doSomething ( String arg1, Integer arg2 ) {
try {
(new ExampleValidator()).doSomething(arg1, arg2);
} catch ( ValidationError e ) {
// return Response with 400
}
}
}
In that way, when I change IExample.doSomething method signature, I have to update Validator because of compile time error. In order for Resteasy NOT TO interpret ExampleValidator as a service, I used resteasy.jndi.resources instead of resteasy.scan, but it fails (Example bean is loaded after resteasy attempts to use it on deploy time).
Any ideas - are there any good patterns of validation?
Or is it possible to somehow get my concept to work?
EDIT: Or, which would be the best, there is some Filter counterpart in Resteasy? Some scheme by which my method (Filter) would be called before actual implementation, but with parameters (arg1, arg2) already parsed?
Thanks in advance, sorry for a lengthy post ;)
Kamil
(1) Probably the cleanest approach is to use Java EE 6 Bean Validation framework. This would require writing custom validation interceptor. In this case you would have to change your methods, so instead of
public Response doSomething ( String arg1, Integer arg2 )
you would use domain object as an argument
public Response doSomething ( JAXBElement<MyDomainObject> myOJaxb )
Then you need to trasform your request, so they provide XML or JSON formatted data, which can ba automatically converted to actual object.
(2) Another option is to use normal ServletFilter.
(3) Prepare custom annotations a'la Bean Validation, then you need to plug-in custom annotations processor (look at project Lombok, as an inspiration).
(4) The simplest solution is to use built-in REST validation
#Path("users/{username: [a-zA-Z][a-zA-Z_0-9]}")
but this applies to path parameters, not query parameters (I think, but didn't check with JAX-RS spec)
Your choice depends on how much flexibility you have with your interfaces and how many time you have.
If you would come up with a generic, pluggable to Resteasy solution similar to suggested in option (3) and make it open source on GitHub many people would love you :)