Jersey client with null put method - java

I am working on a Jersey service client for one of my services and am having trouble determining the best way to pass a null entity through the client's put. On the service side of things this is my endpoint:
#PUT
#Path("/rule/disable/key/{key}")
#Produces(MediaType.APPLICATION_JSON)
public Response disableRuleByKey(#PathParam("key") String key)
throws Exception {
try {
DAL.getWriter().disableRuleByKey(key);
return Response.ok().build();
} catch (BlahException bla) {
throw de;
}
Basically all the method does in the backend is flip a toggle for other parts of the application to use. I'm not sure if put is the correct call to use here (but this was written by a teammate). I know it doesn't even have a JSON payload.
Anyways, on the client side I have this generic putItem() code for all of my clients to use via extends:
public static <T> boolean putItem(Client client, String uri, T item)
throws InterruptedException,
ExecutionException {
Invocation putConfig = client.target(uri).request()
.buildPut(Entity.entity(item, MediaType.APPLICATION_JSON));
Future<Response> asyncResponse = putConfig.submit();
Response response = asyncResponse.get();
return response.getStatus() == Status.OK.getStatusCode();
}
This PUTs into the database fine with a JSON payload, but since the method above doesn't specifically have a payload I was wondering what the best course of action would be. Would modifying the Invocation's .buildPut() to have null in it be okay since I am not passing in a payload.
I am open to modifying the endpoint too but this is what I currently have and can't figure out the best way to send this value to the backend. Should I just modify the endpoint to consume a JSON object rather than passing the key as a #PathParam?

When replacing the state of a resource with a PUT request, you should send the new representation in the request payload.
Have a look the the RFC 7231, the current reference for semantics and content in HTTP/1.1:
4.3.4. PUT
The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. [...]

Related

The gRPC server obtains the request header

I build the server of Java gRPC and want to obtain the data transmitted by the client through the request header. At present, I can only use the ServerInterceptor class to intercept the parsing request header Metadata, but I want to obtain it during service operation. What is the solution?
I tried to access and transfer data through redis, but the gRPC I wrote is multi-data source, the same client request has multiple, if different clients to me a request, but they carry different request headers, other interface names and parameters are the same, It's possible that the request header of a later request will overwrite the redis result of the previous request header, so I can't guarantee the consistency of request and request header!
Use io.grpc.Context to propagate the value to the service implementation, using Contexts.interceptCall(). The jwt-auth example does this as well as some other StackOverflow questions and answers.
Essentially, you just create a new Context with the information you want to communicate, and use Contexts.interceptCall() to make it available to the service as a ThreadLocal. If your service does processing on another thread, you need to either propagate the Context to that other thread or save the value ahead-of-time.
public class AddToContextInterceptor implements ServerInterceptor {
// Context keys use reference equality, so the consumer of the value
// must use this specific object.
public static final Context.Key<MyObject> MY_KEY = Context.key("MY_KEY");
#Override
public <ReqT,RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT,RespT> call, Metadata headers,
ServerCallHandler<ReqT,RespT> next) {
Context newContext =
Context.current().withValue(MY_KEY, metadata.get(SOME_KEY));
return Contexts.interceptCall(newContext, call, headers, next);
}
}
// In the service:
MyObject o = AddToContextInterceptor.MY_KEY.get();

Jenkins - How to bind a url to a java method which returns json string?

I am practicing developing a jenkins plugin. And I want to send an ajax request with some cookies in front end for back end processing and then receive some json response to continue processing my front end logic. Is it possible for me to bind a url to a back end java method with parameters like StaplerRequest and StaplerResponse and simply get the returned json from the method as my response?
After searching around, I found a site introducing how Jenkins stapler works. Particularly, the action method might be helpful for me
According the document I found:
Action Method
If url is of the form "/fooBar/...." and node has a public "action" method named doFooBar(...), then this method is invoked.
to retrieve a json response,
In front end,
$.ajax({
url: "./someUrl/",
}).done(doSomethingOnData(data));
In back end, define a corresponding action method:
public void doSomeUrl(StaplerRequest request, StaplerResponse response) {
Cookie[] myCookies = request.getCookie();
doSometingBasedOnCookies(myCookies);
response.setStatus(200);
response.setContentType("application/json;charset=UTF-8");
String myJson = getJson();
response.getWriter().print(myJson);
}
Yes, you can create simple Rest Method which consume nothing but response back in JSON, something like this
#POST
#Path("/somemethod")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public CommonResponseBean somemethod() {
return response(); // return CommonResponseBean, this will automatically converted into json using jackson
}

Resteasy delegate route to another route

I was wondering if there was a way to delegate to another route in RestEasy.
I.e., something along the lines of, begin in a method inside an RS:
#Path("/api")
public class Foo {
#POST
#Path("/foo")
public Response foo() {
return RestEasy.delegate("GET", "/api/bar");
}
}
Where delegate would return the exact same response as if I had made an HTTP GET request to api/bar, that is, will fall through the proper RS that handles that route, ideally refilling all the necessary request information (headers, params, payload).
I don't want an HTTP redirect as I want it to be transparent to the api user.
I see from the docs/source that org.jboss.resteasy.spi.HttpRequest interface you have access to has a forward method.
It takes a string which would be the path to your other endpoint, but it doesn't let you change the method type (post to a get). But then again neither does the RequestDispatcher forward method you have access to. You aren't allowed to modify the request or the response.
See here:
So really all you can do is directly call your service method or, use an HTTP client to call other REST endpoint inside foo and then stream that back to the client.

How to sign JSON message used by Spring Rest controller?

I have a Spring REST application that accepts JSON messages, written like
#RequestMapping(value = "/myhook", method = RequestMethod.POST,
produces = JSON, consumes = JSON)
public #ResponseBody MyResponse doIt
(#Valid #RequestBody(required = true) MyContractRequest request) {
MyResponse response;
...
return response;
}
This works really well with almost no code to support, but now I have a requirement to sign both response and request.
I started from simply computing the shared signature of all message fields at Java level and assigning it to the dedicated signature field. However this requires to have and maintain code for computing the signatures:
public void update(java.security.Signature sign) throws Exception {
sign.update(name);
sign.update(value);
sign.update(etc);
}
Some people around me expressed opinion that the need to write and maintain this signing code may not be the best design, and it may be better to sign the whole message as a single JSON string. I could fetch the request as a string manually, and then process JSON manually, but I really would like to preserve the Spring controller concepts.
Also, I cannot longer have the signature field in the message itself because the value of this field obviously also changes the signature of the JSON string.
Is there any way to compute the signature of the whole JSON message body on the message departure and arrival, and where to place the signature so it could be passed together with the message? One of the idea is to use the custom HTTP header for the signature. Anyway, how to compute it first?
You can use a servlet filter with Spring MVC and modified your content whatever you want in request and response as well
Example :
http://www.mkyong.com/spring-mvc/how-to-register-a-servlet-filter-in-spring-mvc/
or you can use Spring 3 MVC Interceptor
http://viralpatel.net/blogs/spring-mvc-interceptor-example/

Jersey: making the client to throw the same server exception

I understand that a Jersey-based web service is able to associate exceptions thrown by service methods to desired HTTP return codes (here). Now, is there any chance to make the client generate exactly the same exception that was generated by the service method? I mean, if the server side throws MySpecificException, is there a way to store such information (i.e., the FQN of the exception class) in the HTTP response (automatically, I don't want to turn to methods that build the response explicitly, I want them to return POJOs or void), so that the client can use it to re-throw the same exception?
REST does not specify exception as a response and thus there's no straightforward way to do this (this is not RPC).
However, you can introduce your own convention. For example:
On the provider side you could define ForbiddenException:
public class ForbiddenException extends WebApplicationException {
public ForbiddenException(String code, String readableMessage) {
super(Response.status(Status.FORBIDDEN).entity(new ForbiddenEntity(code, readableMessage)).build());
}
}
(You should probably compose response in ExceptionMapper instead of exception itself, but this is just for demonstration purposes).
And on the consumer side - ClientFilter:
public class ForbiddenExceptionClientFilter extends ClientFilter {
#Override
public ClientResponse handle(ClientRequest cr) throws ClientHandlerException {
ClientResponse response = getNext().handle(cr);
if (response.getStatus() == Status.FORBIDDEN.getStatusCode()) {
ForbiddenEntity reason = response.getEntity(ForbiddenEntity.class);
throw new RemoteResourceForbiddenException(reason.getCode(), reason.getReadableMessage());
}
return response;
}
}
This works as long as server complies with the convention and client uses the client filter.
Please note, this is not "exactly the same" exception - stacktrace is not transferred, however this is the right thing to do as it does not make any sense in client application. If you need stacktrace - it should be printed to logs using ExceptionMapper on server side.

Categories