DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Leveraging Salesforce Using a Client Written In Angular
  • Deep Links With Angular Routing and i18n in Prod Mode
  • Bing Maps With Angular in a Spring Boot Application
  • Zone-Free Angular: Unlocking High-Performance Change Detection With Signals and Modern Reactivity

Trending

  • Designing Memory Architecture for Stateful AI Agents: Short-Term Context and Long-Term Persistence
  • Architecture Review Boards for Generative AI: A Framework for Governance, Risk Management, and Responsible Adoption
  • YAGNI in the Age of AI Coding
  • Part 4: Multi-Agent Orchestration — Pairing Goose With Quarkus Flow State Machines

Draft This article hasn't been published, so readers can't see it.

In moderation This article is waiting for review, so readers can't see it yet.

Deleted This article has been deleted, so readers can't see it.

  1. DZone
  2. Coding
  3. Frameworks
  4. Angular and Spring Webflux

Angular and Spring Webflux

In this article, we'll look at how to combine Angular, Spring Boot, MongoDB, and Webflux to create a full stack web application.

By 
Sven Loesekann
·
Nov. 08, 17 · Tutorial
Post on X (opens in a new tab) Share on LinkedIn (opens in a new tab)
45.5K Views

Join the DZone community Save articles, join the discussion, and download Refcards and Trend Reports with a free account.

Join for free Already a member? Log in

Reactive in the Frontend and the Backend

The project AngularAndSpring shows how to be reactive in the frontend by using Angular and in the backend by using Spring Webflux and the reactive driver of MongoDB. Angular is reactive (non-blocking) by using Observables or Promises. Spring Webflux uses Flux<T> and Mono<T> to be reactive.

Why Reactive?

Normal rest controllers receive a request and a thread is used until the response is sent. In that time, the controller has to retrieve the data the thread is blocking while the data store performs the query. That turns in a performance bottleneck with rising concurrent requests. With reactive programming, the thread can perform other tasks while the data store retrieves the data. That offers a performance boost but requires a change to the reactive programming style.

DZone has a good article with a performance test on this topic.

The Project

The project AngularAndSpring is an example of Angular, Angular Material, Spring Webflux, and reactive MongoDB. It has a Maven build that uses npm. Two languages are supported and request rewriting is implemented.

It reads in the quotes of a few cryptocurrencies and displays them in a table. Each quote has a detail page with its data and a chart of today's quotes. The quotes are read into MongoDB with a scheduled task and read from there to display the pages. The user can sign in/login and then have access to the order books. The goal was to build a project with Angular and a reactive backend to have a reactive (non-blocking) system from the browser to the data store.

Angular Frontend

With the use of Observables or Promises, the Angular frontend is already reactive. The REST services can be used just the same. Here is an example service:

@Injectable()
export class CoinbaseService {
    private _reqOptionsArgs= { headers: new HttpHeaders().set( 'Content-Type', 'application/json' ) };
    private readonly _coinbase = '/coinbase';
    private _utils = new Utils();  

    constructor(private http: HttpClient, private pl: PlatformLocation ) { 
    }

    getCurrentQuote(): Observable<QuoteCb> {
        return this.http.get(this._coinbase+'/current', this._reqOptionsArgs)
          .map(res => this.lowercaseKeys(<QuoteCb>res))
          .catch(this._utils.handleError);
    }

    getTodayQuotes(): Observable<QuoteCbSmall[]> {
        return this.http.get(this._coinbase+'/today', this._reqOptionsArgs)
          .catch(this._utils.handleError);
    }

    private lowercaseKeys(quote: QuoteCb): QuoteCb {
        for (let p in quote) {
          if( quote.hasOwnProperty(p) && p !== '_id' && p !== 'createdAt') {
            quote[p.toLowerCase()] = quote[p];              
          } 
        }     
        return quote;
    }
}

In line 11 the httpClient service gets the Coinbase Quote from the server.

In line 12 the response is mapped to the lowercaseKeys function. It copies the values of the uppercase keys in lowercase keys for further processing.

In line 13 possible errors are handled (logged).

That is the reactive service request of the Angular frontend. The HttpClient no longer needs a map call for '.json()'. It will become the standard HTTP client in the future.

In development setup, the UI is served by Angular-CLI and the REST services are provided by the Spring Boot application. To make the setup work, the Angular-CLI needs to proxy the REST requests to Spring Boot. For that, there is a config file.

Spring Webflux Backend

Spring provides the new reactive Webflux framework. It offers a controller interface that looks familiar and a reactive syntax. Here is an example controller:

@RestController
@RequestMapping("/coinbase")
public class CoinbaseController {

    @Autowired
    private ReactiveMongoOperations operations;

    @GetMapping
    public Flux<QuoteCb> allQuotes() {
        return this.operations.findAll(QuoteCb.class);
    }

    @GetMapping("/today")
    public Flux<QuoteCbSmall> todayQuotesBc() {
        Query query = MongoUtils.buildTodayQuery(Optional.empty());
        return this.operations.find(query,QuoteCb.class)
            .filter(q -> filterEvenMinutes(q))
            .map(quote -> new QuoteCbSmall(quote.getCreatedAt(), quote.getUsd(), quote.getEur(), quote.getEth(), quote.getLtc()));
    }

    @GetMapping("/current")
    public Mono<QuoteCb> currentQuoteBc() {
        Query query = MongoUtils.buildCurrentQuery(Optional.empty());
        return this.operations.findOne(query,QuoteCb.class);
    }

    private boolean filterEvenMinutes(QuoteCb quote) {
        return MongoUtils.filterEvenMinutes(quote.getCreatedAt());
    }
}  

In line 1-2 the Rest Controller is registered.

In line 5-6 the reactive MongoDB driver is injected.

In line 13-14 the "today" rest endpoint is registered and it returns the list of today's quotes.

In line 15 the query for MongoDB is built.

In line 16 MongoDB retrieves the quotes from the collection.

In line 17 the odd minutes are filtered out.

In line 18 the big quotes of type QuoteCb are mapped in a smaller object of type QuoteCbSmall.

Spring Webflux performs the retrieval to the data (non-blocking) and frees the thread until the data has arrived. The reactive programming style is familiar from the functional programming with the collections and streams.

Webflux Client

The client is a scheduled task:

@Component
public class ScheduledTask {
  private static final Logger log = LoggerFactory.getLogger(ScheduledTask.class);
  private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

  private static final String URLCB = "https://api.coinbase.com/v2";

  @Autowired
  private ReactiveMongoOperations operations;

  private WebClient buildWebClient(String url) {
    ReactorClientHttpConnector connector =
                new ReactorClientHttpConnector(options ->
                        options.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000));
    return WebClient.builder().clientConnector(connector).baseUrl(url).build();
  }

  @Scheduled(fixedRate = 60000, initialDelay=15000)
  public void insertCoinbaseQuote() {
    Date start = new Date();
    WebClient wc = buildWebClient(URLCB);
    try {
      operations.insert(
      wc.get().uri("/exchange-rates?currency=BTC")
                      .accept(MediaType.APPLICATION_JSON).exchange()
                      .flatMap(response ->response.bodyToMono(WrapperCb.class))
                      .flatMap(resp -> Mono.just(resp.getData()))
                      .flatMap(resp2 -> {log.info(resp2.getRates().toString()); 
                                             return Mono.just(resp2.getRates());})
      ).then().block(Duration.ofSeconds(3));
      log.info("CoinbaseQuote " + dateFormat.format(new Date()) + " " + (new Date().getTime()-start.getTime()) + "ms");
    } catch (Exception e) {
    log.error("Coinbase insert error "+ dateFormat.format(new Date()));
    }
  }  
}

Line 1 is the @Component Annotations for Spring.

Line 8-9 is the injection of the MongoDB driver.

Line 11-16 creates a WebClient with a timeout.

Line 18 annotates a scheduled method that is run once a minute with an initial delay of 15 sec.

Line 23 is the insert statement for MongoDB.

Line 24 is the Webclient getting the method and the URI set.

Line 25 sets the accepted Media and calls exchange to start the request.

Line 26 takes the JSON body of the response and parses it into the WrapperCb object. Mono means that only one Object of the type is expected.

Line 27-28 unwrap two layers in the response object.

Line 28-29 log the result object and return a Mono<QuoteCb> to MongoDB.

Line 30 blocks the insert operation for a max of 3 seconds.

Line 31 logs the time the operation took.

This code is not reactive. It has a block(...) in line 30 that makes it wait a max of 3 seconds. That means 1 thread of the project is used to read in the data. Each request has 3 seconds to succeed or it fails. The requests are started every 3 seconds. Usually, 3 seconds are more than enough to get and store the response.

Conclusion

With Spring Webflux, Angular gets are a reactive partner. Developers who know Spring will find a familiar syntax with a functional programming model that is easy to learn. For people who want to go a more functional route, there is a more functional API too. MongoDB offers a reactive driver and a nice API/CLI to work with. For all projects that work with DBs that have a functional driver, Spring Webflux offers low hanging fruit.

Spring Framework AngularJS

Opinions expressed by DZone contributors are their own.

Related

  • Leveraging Salesforce Using a Client Written In Angular
  • Deep Links With Angular Routing and i18n in Prod Mode
  • Bing Maps With Angular in a Spring Boot Application
  • Zone-Free Angular: Unlocking High-Performance Change Detection With Signals and Modern Reactivity

Partner Resources

×

Comments

Loading comments

The comments didn't load

Please try again in a moment.

Likes

Loading

The next likes didn't load. Please try again.

The likes didn't load

Please try again in a moment.

See who liked this

Log in or join DZone for free to see who liked this article.

Log in Join for free
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook