Simple default bundle compatible with Scala toolkit
bishabosha opened this issue · 7 comments
Do you think it would be possible to bundle a bunch of defaults into an object for building simple apps in direct style
e.g. JdkHttpServer, Upickle json
Then there can be fewer imports needed
with this simple bundle it would be useful to recommend for bundling with scala toolkit
for example, if I bundle the jdkhttp, and upickle json handlers in one object like this
package scala.toolkit
import sttp.tapir.Tapir
import sttp.tapir.server.jdkhttp
import sttp.tapir.json.upickle.TapirJsonuPickle
import scala.util.Try
object httpserver extends Tapir
with TapirJsonuPickle:
private val ujsonSchema = Schema.schemaForString.map(
s => Try(ujson.read(s)).toOption
)(ujson.write(_))
given Schema[ujson.Value] = ujsonSchema
def ujsonBody = jsonBody[ujson.Value]
export sttp.tapir.Schema
export jdkhttp.{HttpServer, HttpsConfigurator}
export jdkhttp.{JdkHttpResponseBody, JdkHttpServer, JdkHttpServerInterpreter, JdkHttpServerOptions}
then I can make a very simple main app like so
package app
import scala.toolkit.httpserver.*
import java.time.LocalDate
val date = endpoint.get.in("date").out(ujsonBody)
.handleSuccess(_ => ujson.Obj("date" -> LocalDate.now().toString))
@main def launch() =
val server = JdkHttpServer()
.addEndpoint(date)
.port(8080)
.host("localhost")
.executor(scala.concurrent.ExecutionContext.global)
.start()
println("Server started at http://localhost:8080, ctrl-c to stop")
sys.addShutdownHook:
server.stop(0)
An open question is then "what about JDK 21?" - then we could bundle the NettySyncServer instead maybe? we'd have to make a policy in scala/toolkit about JDK support though
Definitely NettySyncServer
is the way to go, it's more feature-full (websockets work, multiparts are coming). Before exports we took this approach: https://tapir.softwaremill.com/en/latest/mytapir.html, though I think it would be most useful for customising schema derivation etc.
ok so would you accept a PR to add a new artefact that can bundle a few of these things in one import? (based on NettySyncServer
, and upickle
, probably add the ujsonBody
directly to the tapir-json-upickle
artifact)
I see also that NettySyncServer requires Ox and is only Scala 3, so this complicates it possibly
Sure why not - we already have a "swagger bundle", the same way we could have a "direct bundle".
I don't understand the ujsonBody
, though? We could also consider using pickler
in that https://tapir.softwaremill.com/en/latest/endpoint/pickler.html
Oh I wasn't aware of this module - it seems good - the reason I defined ujsonBody in this example was so you can do very basic serialisation of ujson.Value
without needing derivation or explicit type parameter, e.g. ujson.Obj("date" -> LocalDate.now().toString)
So there are no default ReadWriters for ujson.Value
s? If so, we could just provide Schema
instances, the way it's done e.g. with circe - no separate methods needed: https://github.com/softwaremill/tapir/blob/7dddc5795669b776c25f2ad7d09be84dc552ec8f/json/circe/src/main/scala/sttp/tapir/json/circe/TapirJsonCirce.scala