I have a mixed Scala/Java Play! application (version 2.5.11). I just moved the WebSocket handling from Java to Scala but the controller receiving the request and returning the response is still in Java. Now I can't access cookies anymore (nor any Http.context)
In more detail:
The Java controller receives the request for a WebSocket and calls the Scala service.
The Scala service produces a play.api.mvc.WebSocket that is then given to the Java controller which more or less just gives it to the client.
Usually WebSockets in Java are of type play.mvc.WebSocket.
Somehow if I use the Scala WebSocket Play! doesn't give me the Http.context: If I call Http.Context.current().request().cookies() I just get a
java.lang.RuntimeException: There is no HTTP Context available from here.
Does anyone know how I can access Http.Context in an controller action that returns a play.api.mvc.WebSocket in Java?
Instead of relying to the java Http.Context class, have you considered just to use the request object that you can pass to the controller method?
The controller method will look like this:
def socket = WebSocket.acceptOrResult[String, String] { request =>
// headers
val headers = request.headers
// cookies
val cookies = request.cookies
// your websocket process
// ...
}
Related
I am confused about how an infinite loop of feign calls might behave.
An example:
Assume I have 2 APIs, A & B.
if I call API A, which in turn calls API B via a feign HTTP call, which in turn calls API A again via feign, will it recognize this and break the call chain?
Quick flowchart of calls:
A -> B -> A -> B ... Repeat infinitely?
I have not tried this code, it is just an idea。
But I am assuming that spring-cloud-starter-feign will provide some methods to resolve this problem? Is this assumption correct?
#PostMapping(RestJsonPath.API_A)
ResponseEntity<byte[]> apiA();
#PostMapping(RestJsonPath.API_B)
ResponseEntity<byte[]> apiB();
Will it execute until it times out or hystrix will stop it?
TL;DR:
Feign will keep the connection open on the initial request from A to B until the pre-configured timeout kicks in. At this point, Feign will time out the request and if you have specified a Hystrix fallback, Spring will use your Hystrix fallback as the response.
Explanation:
spring-boot-starter-feign provides an abstraction layer for writing the HTTP request code. It will not handle potential loops or cycles in your code.
Here is an example spring boot feign client from their tutorials website for demonstration:
#FeignClient(value = "jplaceholder",
url = "https://jsonplaceholder.typicode.com/",
configuration = ClientConfiguration.class,
fallback = JSONPlaceHolderFallback.class)
public interface JSONPlaceHolderClient {
#RequestMapping(method = RequestMethod.GET, value = "/posts")
List<Post> getPosts();
#RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json")
Post getPostById(#PathVariable("postId") Long postId);
}
Notice first that this is an interface - all the code is auto generated by Spring at startup time, and that code will make RESTful requests to the urls configured via the annotations. For instance, the 2nd request allows us to pass in a path variable, which Spring will ensure makes it on the URL path of the outbound request.
The important thing to stress here is that this interface is only responsible for the HTTP calls, not any potential loops. Logic using this interface (which I can inject to any other Spring Bean as I would any other Spring Bean), is up to you the developer.
Github repo where this example came from.
Spring Boot Docs on spring-boot-starter-openfeign.
Hope this helps you understand the purpose of the openfeign project, and helps you understand that it's up to you to deal with cycles and infinite loops in your application code.
As for Hystrix, that framework comes in to play (if it is enabled) only if one of these generated HTTP requests fails, whether it's a timeout, 4xx error, 5xx error, or a response deserialization error. You configure Hystrix, as a sensible default or fallback for when the HTTP request fails.
This is a decent tutorial on Hystrix.
Some points to call out is that a Hystrix fallback must implement your Feign client interface, and you must specify this class as your Hysterix fallback in the #FeignClient annotation. Spring and Hystrix will call your Hystrix class automatically if a Feign request fails.
I have a Java application that gets information on a general purpose channel.
I cannot listen on another port, and the application does not have(or implements) a webserver.
I want to activate some of the application's functionalities via REST API.
I already have the requested URI and parameters(of a single client request), but they are not in an HTTPRequest class.
How can I directly call the Spring REST API, using the data I have?
To illustrate what I want to do:
In myREST.java:
class myREST {
#RequestMapping(value = "/foos", method = RequestMethod.GET)
#ResponseBody
public List<Foo> getAllFoos {
return foos;
}
}
and in another file:
JSONObject restAPICaller(String uri, JSONObject params) {
JSONObject response = springRestAPI.call(uri, "GET", params);
return response;
}
where for instance, my uri is /foos/ , and params is {} (will have content for other examples)
How can I directly call the Spring REST API, using the data I have?
You cannot use an API via an HTTP client without an HTTP server.
I guess you can either:
Embed a server in your app and have it listen on some network port (you can bind to 127.0.0.1, so that the service is not accessible from other machines).
Directly call into the REST API classes (eg: new myREST(). getAllFoos())
Call into the business logic layer your API classes call into (iff you properly structured your code there)
Can anybody provide an example for SSE ( Server sent events) using Spring Rest ? Basically i have a request and the response for it would be sent by the server in multiple chunks. I would like to have the server and client implementation in Spring REST Api without third party rest api like jersey.
There isn't any direct support for SSE in Spring currently but it looks like it will be available in 4.2 which is in RC2 right now
You can see the details here
https://jira.spring.io/browse/SPR-12212
This works via returning an SseEmitter or a ResponseBodyEmitter from the controller methods.
#RequestMapping(value="/stream", method=RequestMethod.GET)
public ResponseBodyEmitter handle() {
ResponseBodyEmitter emitter = new ResponseBodyEmitter();
// Pass the emitter to another component...
return emitter;
}
// in another thread
emitter.send(foo1);
// and again
emitter.send(foo2);
// and done
emitter.complete();
You can see the Reference documentation here
http://docs.spring.io/spring/docs/4.2.0.RC2/spring-framework-reference/htmlsingle/#mvc-ann-async-http-streaming
If I have a #Controller method whose parameter is a #RequestBody param, I usually have to write some jQuery script or something similar to perform an AJAX request with JSON object in order to call that method. If I tried calling that method via a web browser directly, it returns with a Error 415 Unsupported Media Type.
Is there any alternative to just quickly call such method using browser without having to write some jQuery code? Like perhaps a way to write the JSON object in the URL/address bar?
code:
#RequestMapping("testCall")
#ResponseBody
public List<TestObject> getTestCall (#RequestBody TestParams testParams) {
return stuff;
}
public class TestParams {
private Integer testNumber;
//getter/setter for testNumber
}
I thought maybe I could just do:
http://localhost/testCall?testNumber=1
maybe Spring would auto populate a new TestParams instance with that property set to 1 but that didnt work...
maybe I need to do something extra for that?
The whole point of a #RequestBody annotated parameters is for the Spring MVC stack to use the HTTP request body to produce an argument that will be bound to the parameter. As such, you need to provide a request body. Sending a request body is very atypical for a GET request. As such, browsers don't typically support it, at least not when simply entering an address in the address bar and submitting the request.
You'll need to use a different HTTP client, like jQuery. I typically have a small Java project in Eclipse that's setup with an Apache HTTP components client which can send HTTP requests to whatever server. It takes a few seconds/minutes to setup the correct request body and run.
I have spent the last year building a REST API, and by far the best way to exercise that API manually is using the Chrome Extension, Postman. I cannot recommend this tool enough.
https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en
To test your simple example you'll need to invoke a POST (I assume that as you have a request body, but your controller method doesn't define a HTTP Verb) using POSTMAN to your Url (like the following example):
POST /contextRoot/testCall
{
"testNumber": 1
}
If you want to test your API automatically (which I recommend), you can use the excellent Spring Mvc Test project. This allows your to call your API via a rest-like DSL and assert that the response is in the shape you want. More details can be found here:
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/testing.html#spring-mvc-test-framework
you can add request params to the getTestCall method:
#RequestParam(value = "testNumber", required = false, defaultValue = "") String testNumber
There is a chrome app called Advanced REST client. You can pass the data in form of json to your controller using this chrome app. For eg. json data is
id:1,
name:"xyz"
whereas the controller can have #RequestBody Person form.
The Person class would be a POJO having id and name as instance variables. The Spring would automatically map the json data to the form.
I think this is the easiest and simplest way of checking your spring controller.
Check the extension Advanced REST client here
From what I know You can send JSON object to the webbrowser and it will be displayed without further need of AJAX.
useful tutorial:
http://www.mkyong.com/spring-mvc/spring-3-mvc-and-json-example/
I'm writing a simple Google Web Toolkit service which acts as a proxy, which will basically exist to allow the client to make a POST to a different server. The client essentially uses this service to request an HTTP call. The service has only one asynchronous method call, called ajax(), which should just forward the server response. My code for implementing the call looks like this:
class ProxyServiceImpl extends RemoteServiceServlet implements ProxyService {
#Override
public Response ajax(String data) {
RequestBuilder rb = /*make a request builder*/
RequestCallback rc = new RequestCallback() {
#Override
public void onResponseReceived(Response response) {
/* Forward this response back to the client as the return value of
the ajax method... somehow... */
}
};
rb.sendRequest(data, requestCallback);
return /* The response above... except I can't */;
}
}
You can see the basic form of my problem, of course. The ajax() method is used asynchronously, but GWT decides to be smart and hide that from the dumb old developer, so they can just write normal Java code without callbacks. GWT services basically just do magic instead of accepting a callback parameter.
The trouble arises, then, because GWT is hiding the callback object from me. I'm trying to make my own asynchronous call from the service implementation, but I can't, because GWT services assume that you behave synchronously in service implementations. How can I work around this and make an asynchronous call from my service method implementation?
You are mixing up client and server side code. In ProxyServiceImpl, you CANNOT use RequestBuilder. RequestBuilder is a client side class which will only execute in the browser.
A server-to-server http call is always synchronous. Instead of using RequestBuilder, you should make use of a library like HttpClient, get the results and then send it back to the client. That would solve the problem you are facing.
But I should add, you DO NOT want to build a proxy at the application level. You could just as well use a http proxy such as apache's mod_proxy.