Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 08:02
    hamnis commented #4827
  • 05:08
    qwbarch opened #4827
  • 04:05
    rossabaker milestoned #4823
  • 03:59
    rossabaker opened #4826
  • 03:59

    rossabaker on dependencies-0.21.23

    Bump dependencies before 0.21.23 (compare)

  • 03:53
  • 03:40
    rossabaker assigned #2702
  • 03:40
    rossabaker commented #4820
  • 03:39
    rossabaker assigned #1717
  • 03:38
    rossabaker commented #1717
  • 03:30

    rossabaker on main

    Update sbt-jmh to 0.4.2 Merge branch 'main' into update… Update sbt-jmh to 0.4.2 and 1 more (compare)

  • 03:30
    rossabaker closed #4821
  • May 14 19:49

    aeons on sbt-1.5.2

    (compare)

  • May 14 15:12
    alexromanov starred http4s/http4s
  • May 14 14:11
    joshuapassos starred http4s/http4s
  • May 14 12:56
    scala-steward synchronize #4821
  • May 14 12:27

    rossabaker on main

    Update sbt-mdoc to 2.2.21 Merge pull request #4825 from s… (compare)

  • May 14 12:27
    rossabaker closed #4825
  • May 14 10:36
    scala-steward opened #4825
  • May 14 03:21
    scala-steward opened #531
Anton Sviridov
@velvetbaldmime:matrix.org
[m]
Glen Marchesani
@fizzy33
if I have a method as the following what is the idiomatic way to lift that into an HttpRoute ? Noting the use case is the path matching needs to have lookups into a database to see if the path can be satisfied.
def process[F[_]](req: Request[F]): F[Option[Response[F]]]
Since the calculation is expensive I don't want to effectively have to do it twice in a PartialFunction, once for isDefined and another time for actually running it
Glen Marchesani
@fizzy33
nevermind I see it now I just need to create an OptionT.
Fabio Labella
@SystemFw
Kleisli(req => OptionT(process(req)) should do (might need an annotation on req)
Glen Marchesani
@fizzy33
thanks
Martijn
@martijnhoekstra:matrix.org
[m]
I want to take a look at where ember hits the network for inspiration, where do I find that?
Loránd Szakács
@lorandszakacs

@martijnhoekstra:matrix.org Ember uses fs2.io.Network for network stuff:
https://github.com/http4s/http4s/search?q=fs2.io.net.Network

which is used to create an fs2.io.SocketGroup, which then yields fs2.io.Socket, which is then used here:
https://github.com/http4s/http4s/blob/850d66acb9200be241a76a96c249bd88df8aa7f4/ember-server/src/main/scala/org/http4s/ember/server/internal/ServerHelpers.scala#L187

Martijn
@martijnhoekstra:matrix.org
[m]
thanks!
Sean Kwak
@cosmir17
Hello there 😄👋
I want to download a video file via Http4s client. What resp method should I use and type should I use as a return type?
e.g.
        Uri.fromString(cfg.uri.value).liftTo[F].flatMap { uri =>
          client.run(GET(uri)).use { resp =>
            resp.status match {
              case Status.Ok =>
                resp.as???
Christopher Davenport
@ChristopherDavenport

Well naively. resp.body As you have a stream of bytes. You will need an extension to then save that with the right extension. Either that or its actually Multipart which is fairly common for video. Hard to say without more info. Just a reminder some of us are monitoring this channel a bit less since we've moved over to discord.

http://sca.la/typeleveldiscord

Sean Kwak
@cosmir17
That makes sense. I recall I used those when I used async-http-client. I was not sure about http4s.
Drew Boardman
@drewboardman
is using Timer[F] the best way to check how long an HTTP request takes to get back a response?
or is there a better method?
Piotr Portela Kupiec
@piotr.portelakupiec_wh_gitlab
Are people using http4s RC releases in production? I'm working on updating a service to use cats effect 3, and it seems all the CE3 compatible releases for http4s so far are RC
ayeo
@ayeo

Hi all! I got some VO and I am able do encode/decode it to json using circe. Here is the code https://scalafiddle.io/sf/uzrZTq7/2 But I have no idea how to catch the error in my http4s route. I have tried some apporaches found in the net but with no success. Let assume my route looks simple like that

  val jsonApp = HttpRoutes.of[IO] {
    case req @ POST -> Root / "hello" =>
      for {
        todo <- req.as[Todo]
        resp <- Ok(todo.asJson)
      } yield (resp)
  }.orNotFound

In case of error I want to return DecodingFailure details. Now I get 422 with enigmatic message.

ayeo
@ayeo
val jsonApp = HttpRoutes.of[IO] {
    case req @ POST -> Root / "hello" =>
      val x = for {
        todo <- req.as[Todo]
        resp <- Ok(todo.asJson)
      } yield (resp)
      x.handleErrorWith {
        case InvalidMessageBodyFailure(details, cause)  => BadRequest(cause.get.getMessage)
      }
  }.orNotFound
something like this does the work but is ugly :) And I am not happy with the way I access the message
ayeo
@ayeo
another iteration but still not happy with it but at least not bothering with exception :)
val jsonApp = HttpRoutes.of[IO] {
      case req @ POST -> Root / "hello" => for {
        json <- req.as[Json]
        todo <- json.as[Todo] match {
          case Right(todo) => Ok(todo.asJson)
          case Left(errs: DecodingFailure) => BadRequest(errs.getMessage.asJson)
        }
      } yield todo
    }.orNotFound
Christopher Davenport
@ChristopherDavenport
Your response is json, are you sure you don't just want the JsonDebugMiddleware? The errors are enigmatic to not leak internals to clients.
9 replies
Drew Boardman
@drewboardman
is there a client-side equivalent to ResponseTiming?
Christopher Davenport
@ChristopherDavenport
@drewboardman Clock[F].timed
Drew Boardman
@drewboardman
is there some neat algebra that will just do it for me on the client, similar to how this logger works for the server?
Christopher Davenport
@ChristopherDavenport
Or you can do it yourself utilizing Metrics which will report times and conditions to you
Drew Boardman
@drewboardman
i see
and Metrics is in org.http4s?
Christopher Davenport
@ChristopherDavenport
Metrics is in org.http4s.client.middleware for client middleware. You need to construct a metricOps
Drew Boardman
@drewboardman
ok cool thanks
Christopher Davenport
@ChristopherDavenport
Either that or you can build your own like
import org.typelevel.vault._
import org.http4s._
import org.http4s.client._

object Timing {
    val time: Key[FiniteDuration] =  Key[SyncIO, FiniteDuration].unsafeRunSync()
   def apply(client: Client[F]): Client[F] = Client(req: Request[F] => 
        Clock[Resource[F, *]].timed(client.run(req)).map{ case (duration, resp) => resp.withAttribute(time, duration)}
}
Then there will be an attribue on all requests made by the client taht includes the time of the request up until headers are received.
Drew Boardman
@drewboardman
im gonna check out this metrics thing
Christopher Davenport
@ChristopherDavenport
As far as validating user input. If you want to see it and then respond with failures. Generally model the set of valid inputs and then translate that to the set of valid domain objects.
ayeo
@ayeo
how about scenario where user missed some fields. I am not able to parse such request to any object but I still want to let user know what is incorrect/missing?
Drew Boardman
@drewboardman
so this is abstract and I need to implement it?
  def recordTotalTime(
      method: Method,
      status: Status,
      elapsed: Long,
      classifier: Option[String]): F[Unit]
is there a default builder or something?
can i just Logger[F].whatever in there and that will start showing up?
ah, so the F[Unit] could be sending those metrics to prometheus
Drew Boardman
@drewboardman
so for now maybe I could just log the metrics for better visibility
I'm not quite sure what's expected for this function def increaseActiveRequests(classifier: Option[String]): F[Unit]
Drew Boardman
@drewboardman
it's also not obvious what units of time the elapsed is in
it looks like its possibly nanoseconds
Christopher Davenport
@ChristopherDavenport
@drewboardman I think its nanoseconds.

how about scenario where user missed some fields. I am not able to parse such request to any object but I still want to let user know what is incorrect/missing?

Json => Either[NonEmptyList[String], DomainObject]

@ayeo ^
I actually added this as a feature to circe once, but folks weren't very interested in it.
The problem is that decoders are monadic by default, rather than applicative so they don't accumulate errors.
ayeo
@ayeo
@drewboardman thank you :) I will try it out :D
Rohan Sircar
@rohan-sircar
is there a http4s refined module somehwhere? For using refined types in the request DSL/query parameter matchers?
Rohan Sircar
@rohan-sircar
okay, was easy enough to define my own (implicit to do it automagically)
DarkWingMcQuack
@DarkWingMcQuack

hey everybody i have this code which worked with 0.21.0 and now with 1.0.0-m21 it does not work anymore.

implicitly[Client[F]]
        .expectOr(request) { error =>
          for {
            errorBody <- error.as[String]
            _         <- LogWriter.error(s"Failed response. Status=${error.status} Body='$errorBody'")
          } yield HttpError(error.status, errorBody)
        }(jsonDecoder.map(x => decoder.decodeJson(x)))

I get the error : Cannot decode into a value of type String, because no EntityDecoder[F, String] instance could be found. [error] errorBody <- error.as[String]
Did i forget to import something or miss anything here?