How to Create a REST API With Kotlin and Helidon SE?
Hello everyone, Today, we will show you how to create a simple REST API with Helidon SE and Kotlin.
Quick Overview:
- Helidon SE is designed to be a microframework that fortifies the reactive programming model. Helidon SE features three core APIs to engender a microservice -- a web server, configuration, and security -- for building microservices-predicated applications.
- Helidon's web server is an asynchronous and reactive API that runs on top of Netty. The WebServer interface includes support for configuration, routing, error handling, and building metrics and health endpoints.
- The Config loads and processes configuration properties(application.properties or application.yaml) in key/value format.
- The Security class provides support for authentication, sanction, and audit.
Let's begin,
- Helidon SE is designed to be a microframework that fortifies the reactive programming model. Helidon SE features three core APIs to engender a microservice -- a web server, configuration, and security -- for building microservices-predicated applications.
- Helidon's web server is an asynchronous and reactive API that runs on top of Netty. The WebServer interface includes support for configuration, routing, error handling, and building metrics and health endpoints.
- The Config loads and processes configuration properties(application.properties or application.yaml) in key/value format.
- The Security class provides support for authentication, sanction, and audit.
Let's begin,
Final Project Directory:
Maven [pom.xml]:
<?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>io.helidon.applications</groupId> <artifactId>helidon-se</artifactId> <version>2.5.0</version> </parent>
<groupId>com.knf.dev.demo</groupId> <artifactId>helidon-se-rest-hello-world</artifactId> <version>0.0.1-SNAPSHOT</version> <name>helidon-se-rest-hello-world</name> <description>Demo project for Helidon SE</description>
<properties> <version.java>17</version.java> <mainClass>com.knf.dev.demo.helidonseresthelloworld .HelidonSeRestHelloWorldApplication</mainClass> <kotlin.version>1.7.0-Beta</kotlin.version> </properties> <dependencies> <dependency> <groupId>io.helidon.webserver</groupId> <artifactId>helidon-webserver</artifactId> </dependency> <dependency> <groupId>io.helidon.media</groupId> <artifactId>helidon-media-jsonp</artifactId> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jdk8</artifactId> <version>${kotlin.version}</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-test</artifactId> <version>${kotlin.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <version>${kotlin.version}</version> <executions> <execution> <id>compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <phase>test-compile</phase> <goals> <goal>test-compile</goal> </goals> </execution> </executions> <configuration> <jvmTarget>1.8</jvmTarget> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <executions> <execution> <id>compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>testCompile</id> <phase>test-compile</phase> <goals> <goal>testCompile</goal> </goals> </execution> </executions>
<configuration> <source>${version.java}</source> <target>${version.java}</target> <release>${version.java}</release> <forceJavacCompilerUse>true </forceJavacCompilerUse> </configuration> </plugin> </plugins> </build></project>
HelloService.kt
package com.knf.dev.demo.helidonseresthelloworld
import io.helidon.config.Configimport io.helidon.webserver.*import java.util.concurrent.atomic.AtomicReferenceimport javax.json.Json
class HelloService internal constructor(config: Config) : Service { private val greeting = AtomicReference<String>()
init { greeting.set(config["app.message"].asString(). orElse("Empty")) }
override fun update(rules: Routing.Rules) { rules["/", Handler { request: ServerRequest, response: ServerResponse -> getDefaultMessageHandler( request, response ) }] }
private fun getDefaultMessageHandler (request: ServerRequest, response: ServerResponse) { sendResponse(response, "Knowledgefactory") }
private fun sendResponse(response: ServerResponse, name: String) { val message = String. format("%s %s!", greeting.get(), name) val returnObject = JSON.createObjectBuilder(). add("message", message).build() response.send(returnObject) }
companion object { private val JSON = Json .createBuilderFactory(emptyMap<String, Any>()) }}
package com.knf.dev.demo.helidonseresthelloworld
import io.helidon.config.Configimport io.helidon.webserver.*import java.util.concurrent.atomic.AtomicReferenceimport javax.json.Json
class HelloService internal constructor(config: Config) : Service { private val greeting = AtomicReference<String>()
init { greeting.set(config["app.message"].asString(). orElse("Empty")) }
override fun update(rules: Routing.Rules) { rules["/", Handler { request: ServerRequest, response: ServerResponse -> getDefaultMessageHandler( request, response ) }] }
private fun getDefaultMessageHandler (request: ServerRequest, response: ServerResponse) { sendResponse(response, "Knowledgefactory") }
private fun sendResponse(response: ServerResponse, name: String) { val message = String. format("%s %s!", greeting.get(), name) val returnObject = JSON.createObjectBuilder(). add("message", message).build() response.send(returnObject) }
companion object { private val JSON = Json .createBuilderFactory(emptyMap<String, Any>()) }}
application.properties:
server.port=9080app.message=Greetings from
server.port=9080app.message=Greetings from
HelidonSeRestHelloWorldApplication.kt
package com.knf.dev.demo.helidonseresthelloworld
import io.helidon.common.reactive.Singleimport io.helidon.config.Configimport io.helidon.media.jsonp.JsonpSupportimport io.helidon.webserver.Routingimport io.helidon.webserver.WebServerimport java.util.logging.Logger
object HelidonSeRestHelloWorldApplication { private val LOGGER = Logger.getLogger( HelidonSeRestHelloWorldApplication::class.java.name )
@JvmStatic fun main(args: Array<String>) { startServer() }
private fun startServer(): Single<WebServer> {
// Load the default configuration using the // create() method. val config = Config.create()
/* * Helidon's web server is an asynchronous and * reactive API that runs on top of * Netty. The WebServer interface includes support * for configuration, routing, * error handling, and building metrics and * health endpoints. */ val server = WebServer. builder(createRouting(config)). config(config["server"]) .addMediaSupport(JsonpSupport.create()).build()
// Start web server val webserver = server.start() webserver.thenAccept { ws: WebServer -> LOGGER.info("Web server started! http://localhost:" + ws.port() + "/hello") ws.whenShutdown().thenRun { LOGGER.info("Web server is down!") } }.exceptionallyAccept { t: Throwable -> LOGGER. severe("Web startup failed: " + t.message) } return webserver }
private fun createRouting(config: Config): Routing { val helloService = HelloService(config) return Routing.builder() .register("/hello", helloService).build() }}
package com.knf.dev.demo.helidonseresthelloworld
import io.helidon.common.reactive.Singleimport io.helidon.config.Configimport io.helidon.media.jsonp.JsonpSupportimport io.helidon.webserver.Routingimport io.helidon.webserver.WebServerimport java.util.logging.Logger
object HelidonSeRestHelloWorldApplication { private val LOGGER = Logger.getLogger( HelidonSeRestHelloWorldApplication::class.java.name )
@JvmStatic fun main(args: Array<String>) { startServer() }
private fun startServer(): Single<WebServer> {
// Load the default configuration using the // create() method. val config = Config.create()
/* * Helidon's web server is an asynchronous and * reactive API that runs on top of * Netty. The WebServer interface includes support * for configuration, routing, * error handling, and building metrics and * health endpoints. */ val server = WebServer. builder(createRouting(config)). config(config["server"]) .addMediaSupport(JsonpSupport.create()).build()
// Start web server val webserver = server.start() webserver.thenAccept { ws: WebServer -> LOGGER.info("Web server started! http://localhost:" + ws.port() + "/hello") ws.whenShutdown().thenRun { LOGGER.info("Web server is down!") } }.exceptionallyAccept { t: Throwable -> LOGGER. severe("Web startup failed: " + t.message) } return webserver }
private fun createRouting(config: Config): Routing { val helloService = HelloService(config) return Routing.builder() .register("/hello", helloService).build() }}
Local Setup and Run the application
Step1: Download or clone the source code to a local machine. - Click here
Step2: mvn clean install
Step3: Run the Main application
INFO: Web server started! http://localhost:9080/hello
Step1: Download or clone the source code to a local machine. - Click here
Step2: mvn clean install
Step3: Run the Main application
INFO: Web server started! http://localhost:9080/hello