Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple default bundle compatible with Scala toolkit #3914

Open
bishabosha opened this issue Jul 8, 2024 · 7 comments
Open

Simple default bundle compatible with Scala toolkit #3914

bishabosha opened this issue Jul 8, 2024 · 7 comments

Comments

@bishabosha
Copy link

bishabosha commented Jul 8, 2024

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

@bishabosha
Copy link
Author

bishabosha commented Jul 8, 2024

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

@adamw
Copy link
Member

adamw commented Jul 8, 2024

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.

@bishabosha
Copy link
Author

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)

@bishabosha
Copy link
Author

I see also that NettySyncServer requires Ox and is only Scala 3, so this complicates it possibly

@adamw
Copy link
Member

adamw commented Jul 9, 2024

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

@bishabosha
Copy link
Author

bishabosha commented Jul 9, 2024

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)

@adamw
Copy link
Member

adamw commented Jul 9, 2024

So there are no default ReadWriters for ujson.Values? 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants