Skip to content

Instantly share code, notes, and snippets.

@Akashpatel579
Last active July 14, 2023 19:43
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Akashpatel579/33f9a63e98281973ee7ab6cc91a7ca9f to your computer and use it in GitHub Desktop.
Save Akashpatel579/33f9a63e98281973ee7ab6cc91a7ca9f to your computer and use it in GitHub Desktop.
Reactive CRUD APIs with Spring WebFlux
logging.level.org.springframework=ERROR
#logging.level.org.springframework=TRACE
logging.level.com=TRACE
server.port=8080
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=testdb
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.reactiveCRUD</groupId>
<artifactId>universityApp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>universityApp</name>
<description>SpringFlux Restful CRUD example</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.reactiveCRUD.universityApp.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.reactiveCRUD.universityApp.model.Student;
import com.reactiveCRUD.universityApp.service.RegistrationService;
import lombok.AllArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RequestMapping("adminDept")
@AllArgsConstructor
@RestController
public class RegistrationController {
@Autowired
private RegistrationService registrationService;
@GetMapping
public Flux<Student> getAll() {
System.out.println("::will returns ALL Students records::");
return registrationService.getAll();
}
@GetMapping("{id}")
public Mono<Student> getById(@PathVariable("id") final String id) {
System.out.println("::will return a Student record::");
return registrationService.getById(id);
}
@PutMapping("{id}")
public Mono updateById(@PathVariable("id") final String id, @RequestBody final Student student) {
System.out.println("::update the Student record::");
return registrationService.update(id, student);
}
@PostMapping
public Mono save(@RequestBody final Student student) {
System.out.println("will insert the student's record :: "+ student.getId() + " :: " + student.getFirstName());
return registrationService.save(student);
}
@DeleteMapping("{id}")
public Mono delete(@PathVariable final String id) {
System.out.println("::will delete a Student record::");
return registrationService.delete(id);
}
}
package com.reactiveCRUD.universityApp.repository;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
import com.reactiveCRUD.universityApp.model.Student;
@Repository
public interface RegistrationRepository extends ReactiveMongoRepository<Student, String>{
}
package com.reactiveCRUD.universityApp.service;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.reactiveCRUD.universityApp.model.Student;
import com.reactiveCRUD.universityApp.repository.RegistrationRepository;
import lombok.AllArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
@Transactional
@AllArgsConstructor
public class RegistrationService {
@Autowired
private RegistrationRepository registrationRepository;
public Flux<Student> getAll() {
return registrationRepository.findAll().switchIfEmpty(Flux.empty());
}
public Mono<Student> getById(final String id) {
return registrationRepository.findById(id);
}
public Mono update(final String id, final Student student) {
return registrationRepository.save(student);
}
public Mono save(final Student student) {
return registrationRepository.save(student);
}
public Mono delete(final String id) {
final Mono<Student> dbStudent = getById(id);
if (Objects.isNull(dbStudent)) {
return Mono.empty();
}
return getById(id).switchIfEmpty(Mono.empty()).filter(Objects::nonNull).flatMap(studentToBeDeleted -> registrationRepository
.delete(studentToBeDeleted).then(Mono.just(studentToBeDeleted)));
}
}
package com.reactiveCRUD.universityApp.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
@Data
@Builder
@AllArgsConstructor
@Document
@ToString
public class Student {
@Id
private String id;
private String firstName;
private String lastName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
package com.reactiveCRUD.universityApp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UniversityAppApplication {
public static void main(String[] args) {
SpringApplication.run(UniversityAppApplication.class, args);
}
}
@andylib93
Copy link

Hi @Akashpatel579 thank you for this precise summary of your code! I just have one question:

Coud you help me understand public Mono update(final String id, final Student student) of the RegistrationService? As far as I understand the contents of the method, the String id is never used and the new student is just "appended" to all existing ones, or am I missing something? Because the ReactiveMongoRepository does not have an id to search/filter for.

@xbdhshshs
Copy link

Hi @Akashpatel579 thank you for this precise summary of your code! I just have one question:

Coud you help me understand public Mono update(final String id, final Student student) of the RegistrationService? As far as I understand the contents of the method, the String id is never used and the new student is just "appended" to all existing ones, or am I missing something? Because the ReactiveMongoRepository does not have an id to search/filter for.

Yes you are right, the same logic has been used for insert and update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment