Angular client of Spring Boot 2 Reactor Flux API

653
May 16, 2017, at 11:57 AM

How do I create an Angular 4 client for a Java Project Reactor reactive Flux API? The sample below has two APIs: a Mono API; and, Flux API. Both work from curl; but in Angular 4 (4.1.2) only the Mono API works; any ideas how to get Angular 4 to work with the Flux API?

Here's a trivial Spring Boot 2.0.0-SNAPSHOT application with a Mono API and a Flux API:

@SpringBootApplication
@RestController
public class ReactiveServiceApplication {
    @CrossOrigin
    @GetMapping("/events/{id}")
    public Mono<Event> eventById(@PathVariable long id) {
        return Mono.just(new Event(id, LocalDate.now()));
    }
    @CrossOrigin
    @GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Event> events() {
        Flux<Event> eventFlux = Flux.fromStream(
            Stream.generate(
                ()->new Event(System.currentTimeMillis(), LocalDate.now()))
            );
        Flux<Long> durationFlux = Flux.interval(Duration.ofSeconds(1));
        return Flux.zip(eventFlux, durationFlux).map(Tuple2::getT1);
    }
    public static void main(String[] args) {
        SpringApplication.run(ReactiveServiceApplication.class);
    }
}

with a Lombok-ed event:

@Data
@AllArgsConstructor
public class Event {
    private final long id;
    private final LocalDate when;
}

These reactive APIs work from curl as I'd expect:

jan@linux-6o1s:~/src> curl -s http://localhost:8080/events/123
{"id":123,"when":{"year":2017,"month":"MAY","monthValue":5,"dayOfMonth":15,"dayOfWeek":"MONDAY","era":"CE","dayOfYear":135,"leapYear":false,"chronology":{"calendarType":"iso8601","id":"ISO"}}}

and similarly for the non-terminating Flux API:

jan@linux-6o1s:~/src> curl -s http://localhost:8080/events
data:{"id":1494887783347,"when":{"year":2017,"month":"MAY","monthValue":5,"dayOfMonth":15,"dayOfWeek":"MONDAY","era":"CE","dayOfYear":135,"leapYear":false,"chronology":{"calendarType":"iso8601","id":"ISO"}}}
data:{"id":1494887784348,"when":{"year":2017,"month":"MAY","monthValue":5,"dayOfMonth":15,"dayOfWeek":"MONDAY","era":"CE","dayOfYear":135,"leapYear":false,"chronology":{"calendarType":"iso8601","id":"ISO"}}}
data:{"id":1494887785347,"when":{"year":2017,"month":"MAY","monthValue":5,"dayOfMonth":15,"dayOfWeek":"MONDAY","era":"CE","dayOfYear":135,"leapYear":false,"chronology":{"calendarType":"iso8601","id":"ISO"}}}
...

The similarly trivial Angular 4 client with RxJS:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent  implements OnInit, OnDestroy {
  title = 'app works!';
  event: Observable<Event>;
  subscription: Subscription;
  constructor(
    private _http: Http
    ) {
  }
  ngOnInit() {
    this.subscription = this._http
      .get("http://localhost:8080/events/322")
      .map(response => response.json())
      .subscribe(
        e => { 
          this.event = e;
        }
      );
  }
  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

works fine for the Mono API:

"http://localhost:8080/events/322"

but the Flux API:

"http://localhost:8080/events"

never triggers the event handler, unlike curl.

Answer 1

The Flux based controller is producing Server Sent Events (SSE). I don't think the Http client from Angular2 lets you consume SSE...

edit: looks like EventSource is what you need, see this similar question/answer: http://stackoverflow.com/a/36815231/1113486

Answer 2

Going to guess here that the url for /events is the problem because it should produce json to be handled.

@SpringBootApplication
@RestController
public class ReactiveServiceApplication {
    @CrossOrigin
    @GetMapping("/events/{id}")
    public Mono<Event> eventById(@PathVariable long id) {
        return Mono.just(new Event(id, LocalDate.now()));
    }
    @CrossOrigin
    @GetMapping(value = "/events", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Event> events() {
        Flux<Event> eventFlux = Flux.fromStream(
            Stream.generate(
                ()->new Event(System.currentTimeMillis(), LocalDate.now()))
            );
        Flux<Long> durationFlux = Flux.interval(Duration.ofSeconds(1));
        return Flux.zip(eventFlux, durationFlux).map(Tuple2::getT1);
    }
    public static void main(String[] args) {
        SpringApplication.run(ReactiveServiceApplication.class);
    }
}
Rent Charter Buses Company
READ ALSO
Can not get item from List in java

Can not get item from List in java

So I m making an applet and it has to get the item and say at what age is the person in something like alert windowI get error for trying to get an selected item by the index in the list

401
can&#39;t get header subject using POPFetchHeaderOperation

can't get header subject using POPFetchHeaderOperation

I used POPFetchHeaderOperation to get header of a email when developing a email application on andriodI can't get the subject of the header if the email is sent with a PC

290
reading lines from text file in java

reading lines from text file in java

Im trying to readtxt file that contains several similar entities (see below)

387
How to use WebSecurityConfigurerAdapter and WebMvcConfigurerAdapter with web.xml and Java config

How to use WebSecurityConfigurerAdapter and WebMvcConfigurerAdapter with web.xml and Java config

Well, I created a project with Netbeans IDE and Maven, I imported the spring-mvc-archetype that is available in the Netbeans optionsIt uses a web

676