How to use Angular HttpClient to POST, PUT, DELETE data on SpringBoot Rest APIs – Angular 11
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 11
– How to use Angular Http Client to fetch Data from SpringBoot RestAPI – Angular 11
– Angular 11 + Spring JPA + PostgreSQL example | Angular 11 Http Client – Spring Boot RestApi Server
– Angular 11 + Spring JPA + MySQL example | Angular 11 Http Client – Spring Boot RestApi Server
Contents
- I. Technologies
- II. Overview
- III. Practice
- IV. Sourcecode
I. Technologies
– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.1.RELEASE
– Spring Boot: RELEASE
– Angular 11
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})
...
}
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:
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 11
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:
CreateCustomerComponent has 3 main functions:
– onSubmit() & goBack() map with 2 buttons Submit & Back
– newCustomer() maps with button Add to continuously create a 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();
}
}
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 11 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
-> Customer List:
Press Add button. Then input new customer’s info:
Press Submit button,
Press Back button,
Then click to select John, edit firstname from ‘John’ to ‘Richard’. Press Update, then press Back button,
Now click to select Peter, the Application will navigate to Peter details view:
Press Delete button,
IV. Sourcecode
AngularClientPostPutDelete
SpringBootAngularIntegration