Ok(...)
) into the body of new RhoRoutes[IO] { ... }
then everything started working. So my next question is, how can we achieve this without requiring that everything be written in situ?
(implicit responses: ResponseGeneratorInstances[IO])
and try and use this when declaring the routes? ... E.g. "Description of an endpoint" **
POST / "pathhere" ^ jsonOf[IO,MyType] |>> {
(body: MyType) => myDef(body)(this)
}
UUID
. I tried to have a look at the lib code but couldn't find any references to format
Result
locks you into only the "common" status codes.
responses
part is not generated at all.def doOrAccessDenied(user: Option[UserInfo], w: => F[Result.BaseResult[F]])(
implicit F: Monad[F],
): F[Result.BaseResult[F]] = {
user match {
case Some(user) if user.canWrite => w
case Some(_) => Forbidden(Error.forbidden)
case None => Unauthorized(Error.unauthorized)
}
}
BaseResult
is the reason. Here is an example that works for me:def withAuth[T >: F[FORBIDDEN[ErrorMessage]], A <: T](auth: UserDetails, f: UserDetails => A)(implicit c: Concurrent[F]): T = {
if (isAllowed(auth)) {
f(auth)
} else {
Forbidden(ErrorMessage("Some error message"))
}
}
Hi folks!
Could anybody please share an example to generate a classical Swagger file upload?
paths:
/upload:
post:
summary: Uploads a file.
consumes:
- multipart/form-data
parameters:
- in: formData
name: upfile
type: file
description: The file to upload.
I didn't notice this feature in the sources. Is it possible at all?
If not, could you please share your thoughts about how it "should be" implemented?
test("A RhoDsl bits should match route by header") {
import org.typelevel.ci._
import cats.implicits._
case class `header.key1`(value: String)
implicit val h1: Header[`header.key1`, Header.Single] =
Header.create[`header.key1`, Header.Single](
ci"header.key1",
_.value,
s => `header.key1`(s).asRight[ParseFailure]
)
implicit val h1Select = Header.Select.singleHeaders[`header.key1`](h1)
case class `header.key2`(value: String)
implicit val h2: Header[`header.key2`, Header.Single] =
Header.create[`header.key2`, Header.Single](
ci"header.key2",
_.value,
s => `header.key2`(s).asRight[ParseFailure]
)
implicit val h2Select = Header.Select.singleHeaders[`header.key2`](h2)
val srvc = new RhoRoutes[IO] {
GET / "check" >>> H[`header.key1`].capture |>> { (h: `header.key1`) =>
Ok(s"Header #1: ${h.value}")
}
GET / "check" >>> H[`header.key2`].capture |>> { (h: `header.key2`) =>
Ok(s"Header #2: ${h.value}")
}
}.toRoutes().orNotFound
val reqDefault = Request[IO](GET, uri = uri"/check")
val h1Req = reqDefault.withHeaders(Header.Raw.apply(ci"header.key1", "value"))
val h2Req = reqDefault.withHeaders(Header.Raw.apply(ci"header.key2", "value2"))
assertIOBoolean(srvc(h1Req).flatMap(_.as[String].map(_ == "Header #1: value"))) *>
assertIOBoolean(srvc(h2Req).flatMap(_.as[String].map(_ == "Header #2: value2")))
}
Hello there!
Does anyone know if it is possible to customize error messages when decoding POST form data? No matter the reason, whenever a DecodingFailure occurs because the user-uploaded data is "bad", the server response is always "The request body was invalid".
I'd rather return a more detailed error to the user
Hi! Is it possible to somehow use rho with http4s 1.0-232-85dadc2
? I've tried different versions of rho and got Symbol <...> is missing from the classpath
. E.g. when using with rho 0.23.0-M1
:
error: Symbol 'type org.http4s.Header.Select' is missing from the classpath.
This symbol is required by 'method org.http4s.rho.RhoDslHeaderExtractors.H'.
Make sure that type Select is in your classpath and check for conflicting dependencies with
-Ylog-classpath.
A full rebuild may help if 'RhoDslHeaderExtractors.class' was compiled against an incompatible version of org.http4s.Header.
Uri(path = Root / Segment(s"$SwaggerUriSegment?url=/api/${apiVersion.name}/swagger.json"))
^
package com.kiwipowered.stakzcore.apidocs.rho
import cats.effect.{Async, IO, IOApp}
import org.http4s.circe.CirceEntityEncoder
import org.http4s.rho.RhoRoutes
import org.http4s.rho.swagger.models.{Info, Tag}
import org.http4s.rho.swagger.{SwaggerMetadata, SwaggerSupport, SwaggerSyntax}
import org.log4s.getLogger
import org.http4s.blaze.server.BlazeServerBuilder
import org.http4s.rho.swagger.syntax.{io => ioSwagger}
class MinimalExample [F[+_]: Async](swaggerSyntax: SwaggerSyntax[F])
extends RhoRoutes[F]
with CirceEntityEncoder {
import swaggerSyntax._
"Simple hello world route works with a path" **
GET / "a" |>> Ok("Hello world!") // curl localhost:8080/a - gives Hello World!
"Not happy when root" **
GET / root |>> Ok("Hello world!") // curl localhost:8080 - gives not found
}
object Main extends IOApp.Simple {
private val logger = getLogger
private val port: Int = Option(System.getenv("HTTP_PORT"))
.map(_.toInt)
.getOrElse(8080)
logger.info(s"Starting Swagger example on '$port'")
def run: IO[Unit] = {
val metadata = SwaggerMetadata(
apiInfo = Info(title = "Rho demo", version = "1.2.3"),
tags = List(Tag(name = "hello", description = Some("These are the hello routes.")))
)
val swaggerUiRhoMiddleware =
SwaggerSupport[IO].createRhoMiddleware(swaggerMetadata = metadata)
val myRoutes = new MinimalExample[IO](ioSwagger).toRoutes(swaggerUiRhoMiddleware)
BlazeServerBuilder[IO]
.withHttpApp(myRoutes.orNotFound)
.bindLocal(port)
.serve
.compile
.drain
}
}