diff --git a/samples/spring/README.md b/samples/spring/README.md new file mode 100644 index 00000000..46188d99 --- /dev/null +++ b/samples/spring/README.md @@ -0,0 +1,44 @@ +# kohttp-spring sample + +## Description +This is a basic application showing kohttp usage together with Spring Boot. +We are using Spring Boot 2.x, however, Spring Boot 1.x uses similar ideas, except Spring MVC Router DSL. + +Application expose 4 endpoints on `localhost:8080` +- GET /foo +- POST /foo +- GET /foobar +- POST /foobar + +Each endpoint perform various requests using `kohttp`. +Both GET endpoints use defaultHttpClient as a client for `kohttp` requests. +However, both POST endpoints use custom http client with extended `readTimeout` and logging interceptor + +## Build +Build sample as any other SpringBoot application. +```bash +./gradlew clean bootJar +``` + +## Run +Run sample as any other SpringBoot application. +```bash +./gradlew bootRun +``` + +## Test + +### GET requests +Open `localhost:8080/foo` or `localhost:8080/foobar` in your browser. +Or use cURL +```bash +curl -X GET http://localhost:8080/foo +curl -X GET http://localhost:8080/foobar +``` + +### POST requests +Use cURL +```bash +curl -X POST http://localhost:8080/foo +curl -X POST http://localhost:8080/foobar +``` \ No newline at end of file diff --git a/samples/spring/settings.gradle.kts b/samples/spring/settings.gradle.kts index b63a3a51..5fa60fec 100644 --- a/samples/spring/settings.gradle.kts +++ b/samples/spring/settings.gradle.kts @@ -1,2 +1,2 @@ -rootProject.name = "spring_kohttp" +rootProject.name = "spring-kohttp" rootProject.buildFileName = "build.gradle.kts" diff --git a/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring/Configuration.kt b/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring/Configuration.kt new file mode 100644 index 00000000..9bdf39e2 --- /dev/null +++ b/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring/Configuration.kt @@ -0,0 +1,54 @@ +package io.github.rybalkinsd.kohttp.spring + +import io.github.rybalkinsd.kohttp.dsl.httpGet +import io.github.rybalkinsd.kohttp.dsl.httpPost +import okhttp3.Call +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.web.servlet.function.RouterFunction +import org.springframework.web.servlet.function.ServerResponse +import org.springframework.web.servlet.function.router + +/** + * Configuration based on Spring MVC Router DSL + * + * NOTE: available @since Spring 5.2 + */ +@Configuration +class Configuration { + + /** + * Using Router DSL to define MVC controller. + * + * NOTE: available @since Spring 5.2 + */ + @Bean + fun routes(extendedTimeoutClient: Call.Factory): RouterFunction = router { + // maps GET /foobar to httpGet call with defaultHttpClient + GET("/foobar") { + val res = httpGet { + host = "api.github.com" + path = "/" + }.also { it.close() } + + ServerResponse.ok().body(res.code()) + } + + // maps POST /foobar to httpPost call with extendedTimeoutClient + POST("/foobar") { + // using controller with higher timeout due to potentially slow response time + val res = httpPost(extendedTimeoutClient) { + host = "postman-echo.com" + path = "/post" + + body { + json { + "login" to "user" + "email" to "john.doe@gmail.com" + } + } + }.also { it.close() } + ServerResponse.ok().body(res.code()) + } + } +} diff --git a/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring_kohttp/Controller.kt b/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring/Controller.kt similarity index 61% rename from samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring_kohttp/Controller.kt rename to samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring/Controller.kt index c3d4cc6d..beded90e 100644 --- a/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring_kohttp/Controller.kt +++ b/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring/Controller.kt @@ -1,27 +1,36 @@ -package io.github.rybalkinsd.kohttp.spring_kohttp +package io.github.rybalkinsd.kohttp.spring import io.github.rybalkinsd.kohttp.dsl.httpGet import io.github.rybalkinsd.kohttp.dsl.httpPost +import okhttp3.Call +import org.springframework.beans.factory.annotation.Autowired import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RestController +/** + * Annotation based REST controller definition + */ @RestController class Controller { + @Autowired + lateinit var extendedTimeoutClient : Call.Factory + @GetMapping("/foo") fun getHandler(): Int { val res = httpGet { host = "api.github.com" path = "/" - } + }.also { it.close() } return res.code() } @PostMapping("/foo") - fun posthandler(): Int { - val res = httpPost { + fun postHandler(): Int { + // using controller with higher timeout due to potentially slow response time + val res = httpPost(extendedTimeoutClient) { host = "postman-echo.com" path = "/post" @@ -31,7 +40,8 @@ class Controller { "email" to "john.doe@gmail.com" } } - } + }.also { it.close() } + return res.code() } } diff --git a/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring/SpringKohttpApplication.kt b/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring/SpringKohttpApplication.kt new file mode 100644 index 00000000..978162c3 --- /dev/null +++ b/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring/SpringKohttpApplication.kt @@ -0,0 +1,37 @@ +package io.github.rybalkinsd.kohttp.spring + +import io.github.rybalkinsd.kohttp.client.client +import io.github.rybalkinsd.kohttp.interceptors.logging.HttpLoggingInterceptor +import okhttp3.Call +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication +import org.springframework.context.annotation.Bean + +/** + * Basic application context initialization + * ComponentScan will also trigger initialization in + * - [Configuration] + * - [Controller] + */ +@SpringBootApplication +class SpringKohttpApplication { + + /** + * Specific client to handle potentially relatively slow server responses + */ + @Bean + fun extendedTimeoutClient(): Call.Factory = client { + // 10 minutes timeout + readTimeout = 10 * 60 * 1000 + interceptors { + +HttpLoggingInterceptor() + } + } +} + +/** + * Application entry point + */ +fun main(args: Array) { + runApplication(*args) +} diff --git a/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring_kohttp/SpringKohttpApplication.kt b/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring_kohttp/SpringKohttpApplication.kt deleted file mode 100644 index 0d76e401..00000000 --- a/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring_kohttp/SpringKohttpApplication.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.rybalkinsd.kohttp.spring_kohttp - -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.runApplication - -@SpringBootApplication -class SpringKohttpApplication - -fun main(args: Array) { - runApplication(*args) -} diff --git a/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring_kohttp/WebmvcController.kt b/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring_kohttp/WebmvcController.kt deleted file mode 100644 index a09791a4..00000000 --- a/samples/spring/src/main/kotlin/io/github/rybalkinsd/kohttp/spring_kohttp/WebmvcController.kt +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.rybalkinsd.kohttp.spring_kohttp - -import io.github.rybalkinsd.kohttp.dsl.httpGet -import io.github.rybalkinsd.kohttp.dsl.httpPost -import org.springframework.context.annotation.Bean -import org.springframework.stereotype.Component -import org.springframework.stereotype.Controller -import org.springframework.web.servlet.function.RouterFunction -import org.springframework.web.servlet.function.RouterFunctions.route -import org.springframework.web.servlet.function.ServerRequest -import org.springframework.web.servlet.function.ServerResponse -import org.springframework.web.servlet.function.ServerResponse.ok -import java.io.IOException -import javax.servlet.ServletException - - -@Controller -class WebmvcController { - @Bean - fun routes(handler: Handler): RouterFunction { - return route() - .GET("/foobar", handler::handleGet) - .POST("/foobar", handler::handlePost) - .build() - } -} - -@Component -class Handler { - fun handleGet(serverRequest: ServerRequest): ServerResponse { - val res = httpGet { - host = "api.github.com" - path = "/" - } - - return ok().body(res.code()) - } - - @Throws(ServletException::class, IOException::class) - fun handlePost(r: ServerRequest): ServerResponse { - val res = httpPost { - host = "postman-echo.com" - path = "/post" - - body { - json { - "login" to "user" - "email" to "john.doe@gmail.com" - } - } - } - return ok().body(res.code()) - } -}