I am developing a scala web application with http4s and use tapir for endpoints. I am new in it, and now I am looking for a better way to organize my project.
Now I have different classes with endpoints description and server logic in one. They have a java-spring-like name controller. For example:
class SomeController[F[_] : MonadThrow] {
val something: ServerEndpoint[Any, F] =
endpoint
.description("Something")
.post
.in(query[String]("something"))
.out(jsonBody[String])
.errorOut(stringBody)
.serverLogicSuccess {
something => Monad[F].pure(something)
}
val allEndpoints: List[ServerEndpoint[Fs2Streams[F], F]] = List(resend)
}
And then collect them in one configuration, generate open api documentation and http routes. Configuration looks like this:
object RoutesConfiguration {
private val endpoints: List[ServerEndpoint[Fs2Streams[IO], IO]] = new SomeController[IO].allEndpoints
private val openApi: List[ServerEndpoint[Any, IO]] =
SwaggerInterpreter()
.fromEndpoints(endpoints.map(_.endpoint), "Something", "1.0")
val routes: HttpRoutes[IO] = Http4sServerInterpreter[IO]().toRoutes(List(openApi, endpoints).flatten)
}
Is it better to separate endpoints description and server logic? Are there better ways to organize endpoints?
You can separate the logic from the routes e.g. this way:
Then you could combine several endpoints, interpret them twice: once for
HttpRoutes
and once for Swagger. Endpoints would be concerned only about defining Tapir logic and have no idea how you want to implement the business logic because you would pass it through the constructor.