Categories: Uncategorised

Spring Webflux Functional Endpoint – File Upload

In this blog using the Spring WebFlux module, we are going to leverage the functional programming style to define web endpoints using functional endpoints and routing functions.

  1. Functional Endpoints: Spring WebFlux allows to define web endpoints in a functional way using functional programming constructs. Instead of annotating classes and methods as in Spring MVC, we can define routing and handling of requests using functional interfaces and lambda expressions.
  2. Router Functions: Router functions are used to define routes and mappings for incoming requests. These functions are responsible for routing incoming requests to the appropriate handler functions based on criteria such as URL paths, HTTP methods, etc

Here’s an example demonstrating the usage of functional endpoints in Spring WebFlux:

@Controller
public class UploadController {

 @Autowired
 UploadService service;

 @Bean
 @RouterOperations({

  @RouterOperation(path = "/upload", produces = {
    MediaType.APPLICATION_JSON_VALUE }, consumes = "multipart/form-data", method = RequestMethod.POST, operation = @Operation(operationId = "Upload", responses = {
      @ApiResponse(responseCode = Constants.responseCodes.SUCCESS, description = "File Upload Success", content = @Content(schema = @Schema(implementation = Employee.class))),
      @ApiResponse(responseCode = Constants.responseCodes.INTERNAL_SERVER_ERROR, description = "File Upload Failed") }, requestBody = @RequestBody(required = true, content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE, schemaProperties = {
        @SchemaProperty(name = "file", schema = @Schema(type = "string", format = "binary", contentMediaType = MediaType.MULTIPART_FORM_DATA_VALUE)) }))

      )) })

 RouterFunction<ServerResponse> routeUpload() {

  return RouterFunctions.route(
    RequestPredicates.POST("/upload").and(RequestPredicates.contentType(MediaType.MULTIPART_FORM_DATA)),
    req -> req.body(BodyExtractors.toMultipartData()).flatMap(file -> service.upload(file).collectList())
    .flatMap(data -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).bodyValue(data)));
 }
}

In this example, the functional endpoint “/upload” is defined using RouterFunction. The @RouterOperations and @RouterOperation annotations are used to display REST API’s on the swagger-ui. Additional properties like API responses, request body schemas etc are documented using the @Operation annotation. 

The defined route uploads the file contents to DB when accessed via a POST request to “/upload”.

@Service
@Slf4j
public class UploadService {
 
 @Autowired
 UploadRepository repo;

 public Flux<Employee> upload(MultiValueMap<String, Part> file){

  log.info("file upload started...");
  Map<String, Part> part = file.toSingleValueMap();
  FilePart filePart = (FilePart) part.get("file");  
  return DataBufferUtils.join(filePart.content()).map(data ->extracted(data)).
    map(this::processFile).
    flatMapMany(row -> {
   List<Employee> employees = new ArrayList<>();
   for(int i=0;i<row.size();i++) {
    String[] nextLine = row.get(i).split(",");
    Employee emp = Employee.builder().name(nextLine[0]).department(nextLine[1]).build();
    employees.add(emp);    
   }
   return repo.saveAll(employees);
  });
 }

 private String extracted(DataBuffer data) {
  byte[] bytes = data.asByteBuffer().array();
  data.read(bytes);
  DataBufferUtils.release(data);
  return new String(bytes,StandardCharsets.UTF_8);
 }
 
 private List<String> processFile(String line){
  Supplier<Stream<String>> lines = line::lines;
  return lines.get().collect(Collectors.toList());
  
 }
}

Couchbase DB configuration are defined in application.properties:

spring.couchbase.connection-string=localhost
spring.couchbase.password=${PASSWORD}
spring.couchbase.username=${USERNAME}
spring.data.couchbase.auto-index=true
spring.data.couchbase.bucket-name=employees

We can test the API using Swagger which will be available at http://server:port/context-path/swagger-ui.html

Response:

For complete source code: https://github.com/MMahendravarman/Springboot_Examples

mahendravarman.m@gmail.com

Recent Posts

Serverless Functions with Spring Cloud Function, AWS Lambda

Spring Cloud Function is a project within the Spring ecosystem that allows developers to build…

9 months ago

Spring Boot + RabbitMQ – Decoupling Microservices Communication

RabbitMQ is an open-source message broker software that implements the Advanced Message Queuing Protocol (AMQP).…

9 months ago

Spring Integration – Sending files over SFTP

Spring Integration is a powerful extension of the Spring Framework designed to support the implementation…

9 months ago

Spring Cloud Config Client

The Spring Cloud Config Client is a component of the Spring Cloud framework that enables…

10 months ago

Handling CSV in Python

In Python, handling CSV (Comma Separated Values) files is easy using the built-in csv module.…

10 months ago

Spring Cloud Config Server – JDBC Backend

Spring Cloud Config Server provides a centralized location for managing and serving configuration information to…

10 months ago