Angular 9 HttpClient + SpringBoot POST, PUT, DELETE

Angular 9 HttpClient + SpringBoot POST, PUT, DELETE

With previous posts, we had done 2 important things: fetching data from remote server by Angular HttpClient, and navigate among views by Angular Routing.

In this tutorial, we’ll go to next step – work with Rest APIs: How to use Angular HttpClient to POST, PUT & DELETE data on SpringBoot RestAPI Services.

Related Articles:
How to work with Angular Routing – Spring Boot + Angular 9
How to use Angular Http Client to fetch Data from SpringBoot RestAPI – Angular 9
Angular 9 + Spring JPA + PostgreSQL example | Angular 9 Http Client – Spring Boot RestApi Server
Angular 9 + Spring JPA + MySQL example | Angular 9 Http Client – Spring Boot RestApi Server


I. Technologies

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.1.RELEASE
– Spring Boot: RELEASE
– Angular 9

II. Overview

For POST, PUT, DELETE data, We use Angular HTTP Client methods:

– post(url: string, body: any, options?: RequestOptionsArgs): Observable
– put(url: string, body: any, options?: RequestOptionsArgs): Observable
– delete(url: string, options?: RequestOptionsArgs): Observable

Detail implementation:


create(customer: Customer): Promise {
  ...
  return this.http.post(this.customersUrl, JSON.stringify(customer), {headers: this.headers})
  ...
}

update(customer: Customer): Promise {
  ...
  return this.http.put(url, JSON.stringify(customer), {headers: this.headers})
  ...
}

delete(id: number): Promise {
  ...
  return this.http.delete(url, {headers: this.headers})
  ...
}

angular-http-service-architecture

On SpringBoot Server side, we had 3 RequestMappings: @PostMapping, @PutMapping, @DeleteMapping


...

@PostMapping(value="/customer")
public Customer postCustomer(@RequestBody Customer customer){
    ...
}

@PutMapping(value="/customer/{id}")
public void putCustomer(@RequestBody Customer customer, @PathVariable int id){
	...
}

@DeleteMapping(value="/customer/{id}")
public void deleteCustomer(@PathVariable int id){
	...
}

...

About Angular Client‘ views, We design a new Add Customer Form and modify Customer Detail‘s view in the previous post as below:

angular http client post put deletet - add customer form

angular http client post put deletet - edit customer form

III. Practice

In the tutorial, we will re-use the sourcecode that we had done with the previous post. So you should check out it for more details:
How to work with Angular Routing – Spring Boot + Angular 9

Step to do:

With Angular Client:
– Implement new CreateCustomerComponent
– Re-Implement CustomerDetailComponent
– Re-Implement App Routing Module
– Re-Implement AppComponent
– Add new functions for DataService: CREATE – UPDATE – DELETE

With SpringBoot Service:
– Implement new Rest APIs: POST – UPDATE – DELETE

Deployment:
– Integrate Angular App and SpringBoot Server
– Run & Check results.

1. Implement new CreateCustomerComponent

Create new CreateCustomerComponent, see the new project’s structure:

angular http client post put deletet - new project structure

CreateCustomerComponent has 3 main functions:
onSubmit() & goBack() map with 2 buttons Submit & Back

angular http client post put deletet - back - submit button

newCustomer() maps with button Add to continuously create a new customer:

angular http client post put deletet - add new customer

Detail Sourcecode:


import { Customer } from '../customer';
import { DataService } from '../data.service';
import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common';

@Component({
  selector: 'app-create-customer',
  templateUrl: './create-customer.component.html',
  styleUrls: ['./create-customer.component.css']
})
export class CreateCustomerComponent implements OnInit {
  customer = new Customer;
  submitted = false;
  constructor(private dataService: DataService,
              private location: Location) { }

  ngOnInit() {
  }

  newCustomer(): void {
    this.submitted = false;
    this.customer = new Customer();
  }

 private save(): void {
   this.dataService.create(this.customer);
 }

 onSubmit() {
   this.submitted = true;
   this.save();
 }

  goBack(): void {
    this.location.back();
  }
}

About CreateCustomerComponent‘s view, We use submitted variable to control the hidden parts:

<h3>Create Customer Form</h3>
<div [hidden]="submitted">
    <form (ngSubmit)="onSubmit()">
      <div class="form-group">
        <label for="firstname">First Name</label>
        <input type="text" class="form-control" id="firstname" required
        [(ngModel)]="customer.firstname" name="firstname">
      </div>
      
      <div class="form-group">
        <label for="lastname">Last Name</label>
        <input type="text" class="form-control" id="lastname" required
        [(ngModel)]="customer.lastname" name="lastname">
      </div>
      
      <div class="form-group">
        <label for="age">Age</label>
        <input type="number" class="form-control" id="age" required
        [(ngModel)]="customer.age" name="age">
      </div>
      
      <div class="btn-group" >
      	<button class="btn btn-primary" (click)="goBack()">Back</button>
      	<button type="submit" class="btn btn-success">Submit</button>
      </div>
    </form>
</div>

<div [hidden]="!submitted">
	<div class="btn-group ">
    	<h4>You submitted successfully!</h4>
    	<button class="btn btn-primary" (click)="goBack()">Back</button>
    	<button class="btn btn-success" (click)="newCustomer()">Add</button>
    </div>
</div>

[(ngModel)] is used for binding data customer: Customer between views and controllers of Angular Application.

2. Re-Implement CustomerDetailComponent

For CustomerDetailComponent, We add 2 new functions: onSubmit() and delete() for handling 2 buttons: Update and Delete

Details Sourcecode:


import { Component, OnInit, Input } from '@angular/core';

import { Customer } from '../customer';
import { DataService } from '../data.service';

import { ActivatedRoute, Params } from '@angular/router';

import { Location } from '@angular/common';

import 'rxjs/add/operator/switchMap';

@Component({
  selector: 'app-customer-detail',
  templateUrl: './customer-details.component.html',
  styleUrls: ['./customer-details.component.css'],
})

export class CustomerDetailsComponent implements OnInit {

  customer = new Customer() ;
  submitted = false;

  constructor(
    private dataService: DataService,
    private route: ActivatedRoute,
    private location: Location
  ) {}

  ngOnInit(): void {
    this.route.params
      .switchMap((params: Params) => this.dataService.getCustomer(+params['id']))
      .subscribe(customer => this.customer = customer);
  }

  onSubmit(): void {
    this.submitted = true;
    this.dataService.update(this.customer);
  }

  delete(): void {
    this.dataService.delete(this.customer.id).then(() => this.goBack());
  }

  goBack(): void {
    this.location.back();
  }
}

angular http client post put deletet - update - delete button

About CustomerDetailComponent‘s view, We use form tag to handle Customer’s form submittion and
use submitted variable to control the hidden parts:

<h2>Edit Customer Form</h2>
<div [hidden]="submitted">
    <form (ngSubmit)="onSubmit()">
      <div class="form-group">
        <label for="firstname">First Name</label>
        <input type="text" class="form-control" id="firstname" required
        [(ngModel)]="customer.firstname" name="firstname">
      </div>
      
      <div class="form-group">
        <label for="lastname">Last Name</label>
        <input type="text" class="form-control" id="lastname" required
        [(ngModel)]="customer.lastname" name="lastname">
      </div>
      
      <div class="form-group">
        <label for="age">Age</label>
        <input type="number" class="form-control" id="age" required
        [(ngModel)]="customer.age" name="age">
      </div>
      
      <div class="btn-group">
		<button class="btn btn-primary" (click)="goBack()">Back</button>
    	<button type="submit" class="btn btn-success">Update</button>
		<button class="btn btn-danger" (click)="delete()">Delete</button>
	  </div>
      
    </form>
</div>

<div [hidden]="!submitted">
    <h4>Update successfully!</h4>
    <div class="btn-group">
      <button class="btn btn-primary" (click)="goBack()">Back</button>
      <button class="btn btn-success" (click)="submitted=false">Edit</button>
    </div>
</div>

3. Re-Implement App Routing Module

Add new path add for CreateCustomerComponent:


...

const routes: Routes = [
   { path: '', redirectTo: 'customer', pathMatch: 'full' },
   { path: 'customer',  component: CustomersComponent },
   { path: 'add', component: CreateCustomerComponent },
   { path: 'detail/:id', component: CustomerDetailsComponent }
];

...

4. Re-Implement AppComponent

Modify AppComponent‘s view:

<h2 style="color: blue">JSA - Angular Application!</h2>
<nav>
	<a routerLink="customer" class="btn btn-primary active" role="button" routerLinkActive="active">Customers</a> 
	<a routerLink="add" class="btn btn-primary active" role="button" routerLinkActive="active">Add</a>
</nav>
<router-outlet></router-outlet>

5. Add new functions for DataService: CREATE – UPDATE – DELETE

For CREATE, MODIFY, DELETE customers, in DataService, we implement 3 functions:
– create(customer: Customer): Promise
– update(customer: Customer): Promise
– delete(id: number): Promise

3 Angular HTTPClient‘s functions are used for implementation:

– post(url: string, body: any, options?: RequestOptionsArgs): Observable;
– put(url: string, body: any, options?: RequestOptionsArgs): Observable;
– delete(url: string, options?: RequestOptionsArgs): Observable;

Details sourcecode:


...

@Injectable()
export class DataService {
  
  private customersUrl = 'api/customer';  // URL to web API
  private headers = new Headers({'Content-Type': 'application/json'});

  constructor(private http: Http) { }

  ...

  create(customer: Customer): Promise {
    return this.http
      .post(this.customersUrl, JSON.stringify(customer), {headers: this.headers})
      .toPromise()
      .then(res => res.json() as Customer)
      .catch(this.handleError);
  }

  update(customer: Customer): Promise {
    const url = `${this.customersUrl}/${customer.id}`;
    return this.http
      .put(url, JSON.stringify(customer), {headers: this.headers})
      .toPromise()
      .then(() => customer)
      .catch(this.handleError);
  }

  delete(id: number): Promise {
    const url = `${this.customersUrl}/${id}`;
    return this.http.delete(url, {headers: this.headers})
      .toPromise()
      .then(() => null)
      .catch(this.handleError);
  }
   
  ...
}

6. Implement new Rest APIs: POST – UPDATE – DELETE

Implement 3 Rest APIs:


...

@PostMapping(value="/customer")
public Customer postCustomer(@RequestBody Customer customer){
	int id = customers.size() + 1;
	customer.setId(id);
	customers.put(id, customer);
	return customer;
}

@PutMapping(value="/customer/{id}")
public void putCustomer(@RequestBody Customer customer, @PathVariable int id){
	customers.replace(id, customer);
}

@DeleteMapping(value="/customer/{id}")
public void deleteCustomer(@PathVariable int id){
	customers.remove(id);
}

...

>>> Related article: Spring Framework 4.3 New Feature RequestMapping: @GetMapping, @PostMapping, @PutMapping, @DeleteMapping

7. Integrate Angular App and SpringBoot Server

Angular4Client and SpringBoot server work independently on ports 8080 and 4200.
Goal of below integration: the client at 4200 will proxy any /api requests to the server.

Step to do:


{
    "/api": {
        "target": "http://localhost:8080",
        "secure": false
    }
}

– Edit package.json file for “start” script:


...
"scripts": {
    "ng": "ng",
    "start": "ng serve --proxy-config proxy.conf.json",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
},
...

If you want to deploy Angular Application on SpringBoot‘s jar file, you can do following:

– Build the angular4client with command ng build --env=prod
– In pom.xml, use Maven plugin to copy all files from dist folder to /src/main/resources/static folder of SpringBoot server project.

<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
      <execution>
          <id>copy-resources</id>
          <phase>validate</phase>
          <goals><goal>copy-resources</goal></goals>
          <configuration>
              <outputDirectory>${basedir}/target/classes/static/</outputDirectory >
              <resources>
                  <resource>
                      <directory>${basedir}/../angular4client/dist</directory >
                  </resource>
              </resources>
          </configuration>
      </execution>
</executions>
</plugin>

>>> Related article: How to integrate Angular 9 with SpringBoot Web App and SpringToolSuite

8. Run & Check results

Build and Run the SpringBoot project with commandlines: mvn clean install and mvn spring-boot:run
Run the Angular App with command: npm start
Make a request: http://localhost:4200/, results:

–> Response’s data

response data - customer list

-> Customer List:

angular http client post put deletet - customer list

Press Add button. Then input new customer’s info:

add new customer

Press Submit button,

customer post - request data

customer post successfully

Press Back button,

result after add John

Then click to select John, edit firstname from ‘John’ to ‘Richard’. Press Update, then press Back button,

richard update data

edit customer

Now click to select Peter, the Application will navigate to Peter details view:

peter details

Press Delete button,

delete peter data

customer list after delete peter

IV. Sourcecode

AngularClientPostPutDelete
SpringBootAngularIntegration



By grokonez | March 27, 2021.


Related Posts


Got Something To Say:

Your email address will not be published. Required fields are marked *

*