Kotlin Spring WebFlux Annotation-Based RestAPIs – with SpringBoot 2

Reactive programming is about non-blocking applications. And Spring Framework 5 includes a new spring-webflux module, supports Reactive Streams for communicating backpressure across async components and libraries. So in the tutorial, JavaSampleApproach will guide you through the steps for creating a Kotlin Spring WebFlux Annotation-Based RestAPIs with SpringBoot 2.

Related posts:
Kotlin Spring MVC RequestMapping RESTful APIs with @GetMapping, @PostMapping, @PutMapping, @DeleteMapping | SpringBoot Example

I. Technologies

– Java: 1.8
– Maven: 3.5.2
– Spring Tool Suite: Version 3.9.0.RELEASE
– Spring Boot: 2.0.0.M7
– Kotlin 1.1.61
– Spring Boot Starter Webflux
– Postman client

II. Spring WebFlux

Spring Framework 5.0 supports WebFlux with fully asynchronous and non-blocking and does NOT require the Servlet API(Unlike Spring MVC).

Spring WebFlux supports 2 distinct programming models:
– Annotation-based with @RestController
– Functional with Java 8 lambda style

In the tutorial, we will introduce WebFlux with Annotation-based and Kotlin language.
For starting with WebFlux, SpringBoot supports a collection dependency: spring-boot-starter-webflux.

Kotlin sample code:

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping(value="/api/customer")
class RestControllerAPIs {

	@GetMapping
    fun getAll(): Flux {
    	return Flux.fromIterable(ArrayList(custStores.values));
    }
	
	@GetMapping("/{id}")
    fun getCustomer(@PathVariable id: Long): Mono {
		return Mono.justOrEmpty(custStores.get(id))
    }
	
	...
}

reactor.core.publisher.Flux: is a standard Publisher representing a reactive sequence of 0..N items, optionally terminated by either a success signal or an error.
reactor.core.publisher.Mono: Mono is a specialized Publisher that emits at most single-valued-or-empty result.

III. Practice

In the tutorial, We create a Kotlin SpringBoot 2 project as below:

Kotlin Spring WebFlux AnnotationBased RestAPIs - project structure

Step to do:
– Create Kotlin SpringBoot project
– Create data models
– Implement Spring WebFlux APIs
– Run and check results

1. Create Kotlin SpringBoot project

Using SpringToolSuite, create a Kotlin SpringBoot 2 project with Reactive Web dependency spring-boot-starter-webflux:


	org.springframework.boot
	spring-boot-starter-parent
	2.0.0.M7
	 



	true
	UTF-8
	UTF-8
	1.8



	
		org.springframework.boot
		spring-boot-starter-webflux
	
	
		org.jetbrains.kotlin
		kotlin-stdlib-jre8
	
	
		org.jetbrains.kotlin
		kotlin-reflect
	

	
		org.springframework.boot
		spring-boot-starter-test
		test
	
	
		io.projectreactor
		reactor-test
		test
	



	${project.basedir}/src/main/kotlin
	${project.basedir}/src/test/kotlin
	
		
			org.springframework.boot
			spring-boot-maven-plugin
		
		
			kotlin-maven-plugin
			org.jetbrains.kotlin
			
				
					spring
				
			
			
				
					org.jetbrains.kotlin
					kotlin-maven-allopen
					${kotlin.version}
				
			
		
	



	
		spring-snapshots
		Spring Snapshots
		https://repo.spring.io/snapshot
		
			true
		
	
	
		spring-milestones
		Spring Milestones
		https://repo.spring.io/milestone
		
			false
		
	



	
		spring-snapshots
		Spring Snapshots
		https://repo.spring.io/snapshot
		
			true
		
	
	
		spring-milestones
		Spring Milestones
		https://repo.spring.io/milestone
		
			false
		
	

2. Create data models

– Create Address data model:

package com.javasampleapproach.webflux.model

data class Address(
		var street : String? = null,
		var postcode : String? = null
){}

– Create Customer data model:

package com.javasampleapproach.webflux.model

data class Customer(
		var id: Long = -1,
		var firstName: String? = null,
		var lastName: String? = null,
		var age: Int? = null,
		var address: Address = Address()) {
}
3. Implement Spring WebFlux APIs
package com.javasampleapproach.webflux.controller

import javax.annotation.PostConstruct

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
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.javasampleapproach.webflux.model.Customer
import com.javasampleapproach.webflux.model.Address
 
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping(value="/api/customer")
class RestControllerAPIs {
	
	val log = LoggerFactory.getLogger(RestControllerAPIs::class.java);
	
	// Define customer storage
	val custStores = mutableMapOf()
	
	@PostConstruct
    fun initial(){
        custStores.put(1, Customer(1, "Jack", "Smith", 20, Address("NANTERRE CT", "77471")))
        custStores.put(2, Customer(2, "Peter", "Johnson", 25, Address("W NORMA ST", "77009")))
    }
	
	@GetMapping
    fun getAll(): Flux {
    	return Flux.fromIterable(ArrayList(custStores.values));
    }
	
	@GetMapping("/{id}")
    fun getCustomer(@PathVariable id: Long): Mono {
		return Mono.justOrEmpty(custStores.get(id))
    }
	
	@PostMapping("/post")
    fun postCustomer(@RequestBody customer: Customer): Mono>{
		// do post
		custStores.put(customer.id, customer)
		
		log.info("########### POST:" + customer)
		
        return Mono.just(ResponseEntity("Post Successfully!", HttpStatus.CREATED))
    }
	
    @PutMapping("/put/{id}")
    fun putCustomer(@PathVariable id: Long, @RequestBody customer: Customer): Mono>{
		// reset customer.Id
		customer.id = id;
		
		if(custStores.get(id) != null){
			custStores.replace(id, customer)
		}else{
			customer.id = id
			custStores.put(id, customer)
		}
		
		log.info("########### PUT:" + customer)
		return Mono.just(ResponseEntity(customer, HttpStatus.CREATED))
    }
	
	@DeleteMapping("/delete/{id}")
    fun deleteCustomer(@PathVariable id: Long): Mono> {
		val cust = custStores.remove(id)
		if(cust != null){
			log.info("########### DELETE:" + cust)
		}else{
			log.info("########### Don't exist any customer with id = ${id}")
		}
		
		return Mono.just(ResponseEntity("Delete Succesfully!", HttpStatus.ACCEPTED))
    }
}
4. Run and check results

Run the Kotlin SpringBoot project with commandline: mvn spring-boot:run

-> See console’ logs:

s.w.r.r.m.a.RequestMappingHandlerMapping : Mapped "{[/api/customer],methods=[GET]}" onto public reactor.core.publisher.Flux com.javasampleapproach.webflux.controller.RestControllerAPIs.getAll()
s.w.r.r.m.a.RequestMappingHandlerMapping : Mapped "{[/api/customer/delete/{id}],methods=[DELETE]}" onto public reactor.core.publisher.Mono> com.javasampleapproach.webflux.controller.RestControllerAPIs.deleteCustomer(long)
s.w.r.r.m.a.RequestMappingHandlerMapping : Mapped "{[/api/customer/{id}],methods=[GET]}" onto public reactor.core.publisher.Mono com.javasampleapproach.webflux.controller.RestControllerAPIs.getCustomer(long)
s.w.r.r.m.a.RequestMappingHandlerMapping : Mapped "{[/api/customer/post],methods=[POST]}" onto public reactor.core.publisher.Mono> com.javasampleapproach.webflux.controller.RestControllerAPIs.postCustomer(com.javasampleapproach.webflux.model.Customer)
s.w.r.r.m.a.RequestMappingHandlerMapping : Mapped "{[/api/customer/put/{id}],methods=[PUT]}" onto public reactor.core.publisher.Mono> com.javasampleapproach.webflux.controller.RestControllerAPIs.putCustomer(long,com.javasampleapproach.webflux.model.Customer)

– Make a GET all customer request: http://localhost:8080/api/customer

Kotlin Spring WebFlux AnnotationBased RestAPIs - get all customers

– Make a GET customer request: http://localhost:8080/api/customer/1

Kotlin Spring WebFlux AnnotationBased RestAPIs - get a customer

– Make a POST request: http://localhost:8080/api/customer/post

Kotlin Spring WebFlux AnnotationBased RestAPIs - post a customer

– Make a PUT request: http://localhost:8080/api/customer/put/3

Kotlin Spring WebFlux AnnotationBased RestAPIs - put a customer

– Make a DELETE request: http://localhost:8080/api/customer/delete/1

Kotlin Spring WebFlux AnnotationBased RestAPIs - delete a customer

– Make a GET all customers request again: http://localhost:8080/api/customer

Kotlin Spring WebFlux AnnotationBased RestAPIs - get all customers

-> Logs from Kotlin SpringBoot server:

c.j.w.controller.RestControllerAPIs      : ########### POST:Customer(id=3, firstName=Mary, lastName=Taylor, age=27, address=Address(street=S NUGENT AVE, postcode=77571))
c.j.w.controller.RestControllerAPIs      : ########### PUT:Customer(id=3, firstName=Amy, lastName=Taylor, age=24, address=Address(street=E NAVAHO TRL, postcode=77449))
c.j.w.controller.RestControllerAPIs      : ########### DELETE:Customer(id=1, firstName=Jack, lastName=Smith, age=20, address=Address(street=NANTERRE CT, postcode=77471))

IV. Sourcecode

SpringBootKotlinWebFluxAnnotationBased



By grokonez | December 10, 2017.


Related Posts


Got Something To Say:

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

*