How to upsert an expectation with an object callback - java

I feel like I must be missing something obvious but can't seem to figure this one out.
For this project I am writing an http mock with mock-server using upsert so that during the runtime of mock I can change the behavior by upserting an expectation.
So like this:
mock.upsert(
new Expectation(request().withMethod("GET").withPath(MY_PATH))
.thenRespond(response().withBody(json("{\"hello\": \"world\"}")))
.withId(MY_REQUEST_ID));
Now I need some more dynamic behavior so I want to use a callback.
mock.when(request().withMethod("POST").withPath(MY_PATH))
.respond(
httpRequest -> {
final var response = dynamicResponse();
return response().withBody(json(response));
});
Now I can not figure out how to combine the above, so that I have an expectation with a known id, that I can upsert. Expectation does have an thenRespond overload that takes an HttpObjectCallback which sounds like what I am after, but that needs a clientId which I don't no where to get from, or how to pass the actual callback.
Again it feels like I am missing something obvious. Any help is much appreciated.

Related

Representing a request body on HATEOAS link

I have a simple question regarding how do I link an endpoint through HATEOAS if that endpoint requires a valid #RequestBody? I've seen another question regarding this but with no straight answers and so I wonder if the question was not clear enough.
Take a look at the code below:
#GetMapping(path = "/notification/{id}")
#ResponseStatus(HttpStatus.OK)
public NotificationItemResponse getNotification(#PathVariable final String id) {
return notificationItemMapper.toResponse(findUseCase.findNotification(id))
.add(linkTo(methodOn(NotificationItemController.class).getNotification(id)).withSelfRel())
.add(linkTo(methodOn(NotificationItemController.class).saveNotification()).withRel("save")) <- error here, saveNotification expects a valid request body
.add(linkTo(methodOn(NotificationItemController.class).revokeNotification(id)).withRel("revoke"))
.add(linkTo(methodOn(NotificationItemController.class).markNotificationAsSeen(id, "{userName}")).withRel("visualize"));
}
saveNotification() is a method on this controller that requires a request body. That request body is a long json containing a notification message, target users, etc.
It doesn't seem right to create a dummy body just to pass down here, and it hardly seem right to pass a null value. What is the correct approach here? How do I correctly link a method that requires a request body? More specifically, what do I pass down as that request body?
What is the best practice here, other than passing a null or dummy body, as I stated before as a non-optimal solution?
The question is pretty old, but I faced the same issue today, and it looks pretty hard to find the correct answer.
After some research, I found this example in Spring HATEOAS Docs: 3.3 Affordances
#GetMapping("/employees/{id}")
public EntityModel<Employee> findOne(#PathVariable Integer id) {
Class<EmployeeController> controllerClass = EmployeeController.class;
// Start the affordance with the "self" link, i.e. this method.
Link findOneLink = linkTo(methodOn(controllerClass).findOne(id)).withSelfRel();
// Return the affordance + a link back to the entire collection resource.
return EntityModel.of(EMPLOYEES.get(id), //
findOneLink //
.andAffordance(afford(methodOn(controllerClass).updateEmployee(null, id)))
.andAffordance(afford(methodOn(controllerClass).partiallyUpdateEmployee(null, id))));
}
In this case, they use a method afford(...), which works pretty similar to linkTo(...). Looks like passing a null object is a best practice, or at least it is encouraged by the Spring team. So in your case it would look like this:
.add(linkTo(methodOn(NotificationItemController.class).saveNotification(null)).withRel("save"))

Using CompletableFuture.allOf on a variable number of objects

Please bear with me, i dont usually use spring and havent used newer versions of java (I say newer I mean anything past prob 1.4)
Anyway, I have an issue where I have to do rest calls to do a search using multiple parallel requests. Ive been looking around online and I see you can use CompletableFuture.
So I created my method to get the objects I need form the rest call like:
#Async
public CompletableFuture<QueryObject[]> queryObjects(String url)
{
QueryObject[] objects= restTemplate.getForObject(url, QueryObject[].class);
return CompletableFuture.completedFuture(objects);
}
Now I need to call that with something like:
CompletableFuture<QueryObject> page1 = QueryController.queryObjects("http://myrest.com/ids=[abc, def, ghi]);
CompletableFuture<QueryObject> page2 = QueryController.queryObjects("http://myrest.com/ids=[jkl, mno, pqr]);
The problem I have is that the call needs to only do three ids at a time and there could be a list of variable number ids. So I parse the idlist and create a query string like above. The problem with that I am having is that while I can call the queries I dont have separate objects that I can then call CompletableFuture.allOf on.
Can anyone tell me the way to do this? Ive been at it for a while now and Im not getting any further than where I am now.
Happy to provide more info if the above isnt sufficient
You are not getting any benefit of using the CompletableFuture in a way you're using it right now.
The restTemplate method you're using is a synchronous method, so it has to finish and return a result, before proceeding. Because of that wrapping the final result in a CompletableFuture doesn't cause it to be executed asynchronously (neither in parallel). You just wrap a response, that you have already retrieved.
If you want to benefit from the async execution, then you can use for example the AsyncRestTemplate or the WebClient .
A simplified code example:
public ListenableFuture<ResponseEntity<QueryObject[]>> queryForObjects(String url) {
return asyncRestTemplate.getForEntity(url, QueryObject[].class);
}
public List<QueryObject> queryForList(String[] elements) {
return Arrays.stream(elements)
.map(element -> queryForObjects("http://myrest.com/ids=[" + element + "]"))
.map(future -> future.completable().join())
.filter(Objects::nonNull)
.map(HttpEntity::getBody)
.flatMap(Arrays::stream)
.collect(Collectors.toList());
}

Serving static page from custom scala action in Play Framework

I'm new to scala, but have some experience using the play framework in Java. I've added the SecureSocial authentication library, which defines a SecuredACtion, and it seems to be working correctly. However, I'm having trouble understanding the expected content within the custom action in scala code.
Here's my controllers class. Ideally, "index" would simply redirect the authenticated request to "unprotectedIndex" somehow, but that doesn't seem to be possible. So if not, next best thing is simply to serve the file directly from inside of the secured action, but that's also not working.
What is missing from my code?
object Application extends Controller with securesocial.core.SecureSocial {
// this doesn't compile, but it's a long scala exception that I don't know how to fix.
def index = SecuredAction { implicit request =>
Assets.at("/public", "index.html").apply(request)
}
def unprotectedIndex = Assets.at("/public", "index.html")
}
It seems like it's expecting a SimpleResult but getting a Future[SimpleResult] - this feels like it shouldn't be complicated, but what am I missing?
It seems like you are using play framework 2.2. There were some changes and most methods return Future[SimpleResult] instead of just Result or SimpleResult. You can check if you are able to do like this: def index = SecuredAction.async {...} (but I'm almost sure you can't).
You can use this approach to make it work correctly:
import scala.concurrent.Await
import scala.concurrent.duration._
def index = SecuredAction { implicit request =>
Await.result(Assets.at("/public", "index.html").apply(request), 5 seconds) //you can specify you maximum wait time here
}
EDIT
Even one more thing to simplify:
Await.result(unprotectedIndex(request), 5 seconds)
So you can call your unprotectedIndex from your index Action
So, just by looking at syntax highlighting in my IDE I have been able to get something that seems to compile and work but looks deeply wrong to me.
I changed it to this:
def index = SecuredAction { implicit request =>
Assets.at("/public", "index.html").apply(request).value.get.get
}
Is that the correct way to do this? It looks really weird to me, am I just not familiar with the idioms?

How can I configure Square's Retrofit Client to handle a request with a variable number of parameters

I'm building an Android App and am using Square's Retrofit library for short-lived network calls. I'm relatively new to Java and Android. Until now I've constructed requests like so:
#GET("/library.php")
void library(
#Query("one_thing") String oneThing,
#Query("another_thing") String anotherThing,
Callback<Map<String,Object>> callback
);
And called them like so:
service.library(oneThing, anotherThing, callback);
I need to implement a request that accepts a variable number of parameters, not more than 10 or so. It's cumbersome to have to define them individually and pass null or something for the ones that aren't present for a given request. Is there a way to define an interface for a request such that it accepts a variable number or parameters and auto-constructs #Querys for each element in the parameter dictionary/map? Something like this:
#GET("/library.php")
void library(
Map<String,Object> parameters,
Callback<Map<String,Object>> callback
);
service.library(parameters, callback);
Thanks in advance for any tips.
Edit: passing null for params that aren't pertinent to the request wont work in this case. Ideally I'd be able to set/create #Querys based on the parameter dictionary, so that keys wont become a #Query if their value is null.
Edit: I'm specifically looking for a solution that works with GET requests.
You could always try passing the parameters as a HTTP Body instead, such as in this example (note: I'm the author)
But as you suggest, use a Map with your values instead, so this might work for you:
#POST("/library.php")
public void library(#Body Map<String, Object> parameters, Callback<Map<String,Object>> callback);
It's a bit late but I'll post it anyway just in case someone found the same problem on Google.
They've introduced the Annotation #QueryMap
This annotation let you pass and object that implements Map class, is not as nice as Post requests that let's you pass an Object as parameter but it get the works done.
#GET("/library.php")
public void library(#QueryMap Map<String, Object> parameters, Callback<Map<String,Object>> callback);

Is it possible to get a #PathParam or #QueryParam from the MessageBodyReaderContext in a RestEASY MessageBodyReaderInterceptor?

My service:
#POST
public String setData(#QueryParam("id") Long is, MyObject payload) {
...
}
or
#POST
public String setData(#PathParam("id") Long is, MyObject payload) {
...
}
My interceptor on the server:
Object read(MessageBodyReaderContext context) throws IOException, WebApplicationException {
Class mypayloadtype = context.getType;
InputStream mypayloadinpustream = context.getInputStream();
Long myidparam = ???????? // how to get the query or path param here?
}
EDIT: To be a bit more concrete:
What I'd like to do is to grab the XML and store it based on the parameters in a separate audit system. Maybe PreProcessInterceptor / PostProcessInterceptor are the better choices?
Any hints or alternative ways to get the param when the xml is still available for preprocessing?
Miguel
I just stumbled over the same problem today. I needed the #PathParams and #QueryParams in the read() method and ended up with something like this:
public class MyInterceptor implements PreProcessInterceptor, MessageBodyReaderInterceptor
{
private static ThreadLocal<UriInfo> uri = new ThreadLocal<UriInfo>();
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
{
uri.set(request.getUri);
...
}
public Object read(MessageBodyReaderContext context)
{
String param = uri.get().getPathParameters().getFirst("myidparam");
...
}
}
Although when thinking about it now - I'm not quite sure, if just using PreProcessInterceptor/PostProcessInterceptor will also do the trick for my (and maybe your) problem. I'll have another look tomorrow.
I am not an expert on the topic but to me it seems as if the MessageBodyReaderContext interface does not really know if it is on the server or the client side, so it cannot expose the request or its parameters / path parts etc.
So as far as I know this is not possible.
If your code knows that it lives on the server side of the rest
communication, maybe you can use a servlet filter to store the request
in a ThreadLocal and then access it from there while the request is
handled, somewhat similar to RequestContextFilter / RequestContextHolder from the spring framework? (Then the request object does not know anything about the annotations of your service, but instead one has to extract the information manually from the request. This means to have the same information in two places, so there has to be a better solution ...)
Edit: after looking at some examples I get the vague feeling that if you want to read the input stream to create an object and add path parameters to it, MessageBodyReaderInterceptor is simply not the way to go. Instead set up a MessageBodyReader which constructs the object from the request body data, and this then will be passed into the public String setData(#PathParam("id") Long is, MyObject payload), assuming that this method is annotated with a #Consumes which matches the #ConsumeMime annotation for the MessageBodyReader. There you might be able in the setData to set the missing id on the object read from the request body. Some examples related to this seem to be here: How to get full REST request body using Jersey? (but for Jersey, not jBoss :-/)
However I am not sure if that works for you, and I also feel I completely overestimated my ability to answer this question appropriately, so I hope someone more knowledgeable comes in with a better solution.

Categories

Resources