spring-projects-experimental / spring-fu

Configuration DSLs for Spring Boot
Apache License 2.0
1.67k stars 139 forks source link

Ability to create endpoints/routes dynamically (IE and endpoint creating another endpoint at runtime)? #371

Open GavinRay97 opened 3 years ago

GavinRay97 commented 3 years ago

Hello, this is quite a fantastic library you've made available!

The only thing I haven't been able to figure out from the examples available + source code is whether it's possible to programmatically/dynamically create new routes?

To test this, I tried to have an endpoint /sample create a route /new, but what gets returned is just the empty "whitelabel" page.

This is with Spring Boot 2.6-SNAPSHOT and the 0.4.5-SNAPSHOT of Spring-Fu:

package org.hasura.polyglot

import scala.beans.BeanProperty
import reactor.core.publisher.Mono
import org.springframework.fu.jafu.Jafu.reactiveWebApplication
import org.springframework.fu.jafu.webflux.WebFluxServerDsl
import org.springframework.fu.jafu.webflux.WebFluxServerDsl.webFlux
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse
import org.springframework.web.reactive.function.server.ServerResponse.ok
import org.springframework.web.reactive.function.server.RouterFunctions

case class Sample(@BeanProperty message: String)

class SampleService:
  def generateMessage(): String = "Hello world!"

class SampleHandler(private var sampleService: SampleService):
  def hello(request: ServerRequest): Mono[ServerResponse] =
    ServerResponse.ok().bodyValue(sampleService.generateMessage())

  def json(request: ServerRequest): Mono[ServerResponse] =
    ServerResponse.ok().bodyValue(new Sample(sampleService.generateMessage()))

def mkRoutes(server: WebFluxServerDsl)(app: RouterFunctions.Builder) =
  val handler = server.ref(classOf[SampleHandler])

  app.GET("/sample", req => {
    println("Called /sample handler, attempting to dynamically create endpoint...")
    app.GET("/new", req => {
      println("/new endpoint created from within /sample")
      ServerResponse.ok().bodyValue("dynamically created during GET /sample request")
    })
    ServerResponse.ok().bodyValue("hello")
  })

  app.GET("/", req => {
    handler.hello(req)
  })

  app.GET("/api", handler.json)

object Application:
  val app = reactiveWebApplication(a => {
    a.beans(b => {
      b.bean(classOf[SampleHandler])
      b.bean(classOf[SampleService])
    })

    a.enable(
        webFlux(server =>
          server
            .port(if server.profiles().contains("test") then 8181 else 8080)
            .router(mkRoutes(server))
            .codecs(_.string().jackson())
        )
    )
  })

  def main(args: Array[String]): Unit = app.run(args)