DEV Community

Tomasz Flis
Tomasz Flis

Posted on

Sending a POST request to different APIs in Angular using RxJS

Topic

RxJs is a powerful tool to play with streams, make operations on them. This demo project is an example of sending one form value to two different APIs (with a toggle button deciding which one should be used).

Setup project

I created an angular project by typing (answered CLI question by default):

ng new store-data-example
Enter fullscreen mode Exit fullscreen mode

I love using Angular Material, so in the root directory, I typed (default answers):

ng add @angular/material 
Enter fullscreen mode Exit fullscreen mode

Now my project is ready to code.

Service

To be able to make HTTP calls I added HttpClientModule to imports inside AppModule file (from @angular/common/http).
I made a service to make HTTP calls to two endpoints separatly.
The first one is firing to Httpbin endpoint.
The second one is firing to JSONPlaceholder.
Here is full code of service:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class EndpointService {
  constructor(private http: HttpClient) {}

  sendBin(data: any): Observable<boolean> {
    console.info('HTTP BIN sent');
    return this.http.post('https://httpbin.org/post', { data }).pipe(
      map(_ => true),
      catchError(error => of(false))
    );
  }

  sendJsonPlaceholder(data: any): Observable<boolean> {
    console.info('JSON Placeholder sent');
    return this.http.post('https://jsonplaceholder.typicode.com/posts', { data }).pipe(
      map(_ => true),
      catchError(error => of(false))
    );
  }
}


Enter fullscreen mode Exit fullscreen mode

I simplified it, and all success I am treating as positives and all errors as negatives.

  • map operator converts one value to another
  • catchError operator is listening for any errors on stream Of course, I could use the error object inside catchError to check response status. Both methods return observable with the boolean results depending on the HTTP response.

The form

To be able to use some Angular Material elements and angular forms I imported some modules into AppModule:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule } from '@angular/common/http';
import { MatButtonModule } from '@angular/material/button';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule,
    MatButtonModule,
    ReactiveFormsModule,
    MatFormFieldModule,
    MatInputModule,
    MatSnackBarModule,
    FormsModule,
    MatSlideToggleModule,
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

My form is really simple, with two fields:

  form = this.formBuilder.group({
    firstName: [null],
    lastName: [null],
  });
Enter fullscreen mode Exit fullscreen mode

In constructor, I added three classes:

    private endpointService: EndpointService,
    private formBuilder: FormBuilder,
    private snackBar: MatSnackBar
Enter fullscreen mode Exit fullscreen mode
  • endpointService my HTTP service
  • formBuilder Angular reactive form builder
  • snackBar Angular Material Snack Bar

My component has also two other properties:

  • subject RxJS Subject which allows me to pass data to the service
  • enpointToggle true for JSONPlaceholder, false for HttpBin

I am sending form value to the subject by using the next method:

  onSubmit(): void {
    this.subject.next(this.form.value);
  }
Enter fullscreen mode Exit fullscreen mode

Depending on the enpointToggle value I am sending data to one of the endpoints:

    this.subject
      .asObservable()
      .pipe(
        switchMap(value => iif(
          () => this.enpointToggle,
          this.endpointService.sendJsonPlaceholder(value),
          this.endpointService.sendBin(value),
        ))
      )
      .subscribe(result => this.snackBar.open(result ? `Send to ${this.endpoint}` : 'Error', '', { duration: 3000 }))
Enter fullscreen mode Exit fullscreen mode
  • asObservable allows me to use the subject as observable and treat it as a stream
  • pipe method is for working with data from the stream
  • switchMap operator for switching from one observable (with form value) to another (HTTP call)
  • iif function takes three arguments (and returns observable):
    • first takes a function which result decides which observable should be subscribed
    • second takes observable which is subscribed when the first function returns true
    • third takes observable which is subscribed when the first function returns false IMPORTANT! iif evaluates both expressions in any case, but service will fire HTTP call only in one of them (depending on boolean return)
  • subscribe calls open method on snackBar to show notification

The HTML code is also simple:

<form [formGroup]="form" (ngSubmit)="onSubmit()">

  <mat-form-field appearance="fill">
    <mat-label>First name</mat-label>
    <input matInput formControlName="firstName">
  </mat-form-field>

  <mat-form-field appearance="fill">
    <mat-label>Last name</mat-label>
    <input matInput formControlName="lastName">
  </mat-form-field>

  <button type="submit" mat-flat-button color="primary">Send</button>

</form>
<mat-slide-toggle [(ngModel)]="enpointToggle">HttpBin / JSONPlaceholder</mat-slide-toggle>
Enter fullscreen mode Exit fullscreen mode

Link to repo.

Top comments (1)

Collapse
 
kagol profile image
Kagol

This is very useful to me, thank you for sharing! 👍🏻