Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Feb 12 14:20
    sergeykolbasov commented #1204
  • Feb 12 00:10
    codecov-io commented #1204
  • Feb 12 00:10
    rpless review_requested #1204
  • Feb 12 00:10
    rpless review_requested #1204
  • Feb 12 00:10
    rpless commented #1204
  • Feb 12 00:03
    codecov-io commented #1204
  • Feb 12 00:03
    rpless synchronize #1204
  • Feb 11 03:46
    sergeykolbasov edited #1204
  • Feb 11 01:17
    rpless commented #1204
  • Feb 11 01:10
    rpless commented #1204
  • Feb 11 00:50
    rpless edited #1204
  • Feb 11 00:50
    rpless edited #1204
  • Feb 11 00:50
    rpless edited #1204
  • Feb 11 00:50
    rpless edited #1204
  • Feb 11 00:50
    rpless edited #1204
  • Feb 11 00:49
    codecov-io commented #1204
  • Feb 11 00:49
    rpless synchronize #1204
  • Feb 11 00:48
    codecov-io commented #1204
  • Feb 11 00:48
    rpless synchronize #1204
  • Feb 10 16:07
    rpless edited #1204
Sergey Kolbasov
@sergeykolbasov
I'll spend some time in the next days working on proper documentation
@joroKr21 I'm not huge fan of *Local things personally. It's even worse than implicits if you think about it. You should believe that someone somewhere put the required data into the magical box of *Local before the moment you're going to use it
This message was deleted
Georgi Krastev
@joroKr21
It's not so difficult to arrange as long as you don't have too many ends of the world. Besides, how is it different than providing a default NoopLogger to ReaderT?
You also need to make sure that someone is calling local with a new tracing logger.
Sergey Kolbasov
@sergeykolbasov
well, at least it's an explicit requirement to have one
you might as well have no NoopLogger at all and just run the Endpoint.Compiled[ReaderT[F[_], Ctx, *]] inside of Endpoint.Compiled[F[_]] when there is an access to request to build a proper logger right away
Pavel Borobov
@blvp

Hello everyone.
I faced one little problem using finch to build json REST API application.
In my application I have 2 entities User and Pet and they both have CRUD like operations.
Both API groups have their own encoders and decoders (I'm using circe).

class UserResources[F[_]](userRepo: UserRepo[F]) extends Endpoint.Module[F] with UserCodecs {
   val create: Endpoint[F, User] = post("user" :: jsonBody[User]) { user: User => userRepo.save(user).map(Ok(_)) }
   val get: Endpoint[F, User] = get("user" :: path[Long]) { userId: Long => userRepo.findById(userId).map(Ok(_)) }
   ...
   val endpoints = (create :+: get)
}
class PetResources[F[_]](petRepo: PetRepo[F]) extends Endpoint.Module[F] with PetCodecs {
   val create: Endpoint[F, User] = post("pet" :: jsonBody[Pet]) { pet: Pet => petRepo.save(user).map(Ok(_)) }
   val get: Endpoint[F, User] = get("pet" :: path[Long]) { userId: Long => petRepo.findById(userId).map(Ok(_)) }
   ...
   val endpoints = (create :+: get)
}

Then I use them in this fashion:

val allEndpoints = (new UserResources(repo).endpoints :+: new PetResources(repo2).endpoints)
val api  = Bootstrap.serve[Application.Json](allEndpoints).toService

But this call require same instances of Encoder/Decoderwhich are defined in *Codecs trait for .toService call to materialise the service. I understand why we should have instances in both situations.

Could you please suggest to me how I can better organise code in similar fashion, but without codecs instances duplicate?

Sergey Kolbasov
@sergeykolbasov

Hi @blvp

Best practice in Scala is to put type classes instances for specific types into companion objects whenever is possible

Compiler picks it up from there on its own without any imports.

If you need to describe it for types outside of your application (like library types), you might as well to keep it inside a package object (or just an object) and import those implicits from there

Pavel Borobov
@blvp
Yeah, but it will require it to be imported firstly inside of your Resource class and in component that will combine several resources into a service. So in my example it will require both instances of User and Pet in the code where I call . toService
Sergey Kolbasov
@sergeykolbasov
You don't need to import anything if you put implicit encoders and decoders into corresponding companion objects (User and Pet in your example)
Kevin Pei
@kpei
Hi guys, new to finch, if i have an Endpoint[A], how do I go about getting it's defined path? e.g val endpoint = get("foo" :: "bar") { //something } how do I extract the "foo/bar" from the endpoint?
Ryan Plessner
@rpless
Hi @kpei one approach would be to use root to access the raw finagle request. something like val endpoint = get(root :: "foo" :: "bar")((request) => ...). request.path should give you the full path
Guillaume Balaine
@Igosuki
Hi there
I’m migrating from http4s to Finch, has anyone ever used a bracket that signals IO[ExitCode] upon Finagle server termination ?
I want to join a Finagle server concurrently with other fs2.Streams I have running in the background
Sergey Kolbasov
@sergeykolbasov

Hi @Igosuki I experimented with it once, don't remember the way but it's possible for certain

But to clarify, what do you mean exaclty by upon Finagle server termination? Because usually you shut it down all together with the whole application, and Http.serve returns forever-running Twitter Future

Guillaume Balaine
@Igosuki
I should have mentionned additionnally to mounting the server (so I can just wrap the server in a resource and close it as it gets discarded) I have a repl workflow where I restart it
But I solved it no worries
There’s actually an example in the repo that looked very similar to what I had
Another question, is throwing exceptions the idiomatic way of handling errors in Finch ? My entire code returns errors, I guess I have to write my own error-based Response creators
Guillaume Balaine
@Igosuki
What’s the best practice if endpoints are in multiple files ?
ComFreek
@ComFreek
import io.circe.generic.auto._ gives me an error about the subpackage generic not being found. What SBT dependencies do I need for this?
Currently I have libraryDependencies ++= Seq( "com.github.finagle" %% "finchx-circe" % "0.31.0", "com.github.finagle" %% "finchx-generic" % "0.31.0" )
ComFreek
@ComFreek
Got it, opened #1194 to improve docs.
Sergey Kolbasov
@sergeykolbasov
@Igosuki we just keep our endpoints grouped in separate classes per domain, instantiate them in DI and then manually build a coproduct of all the endpoints
classes instead of objects due to polymorphic F and dependency injection in class constructor
Richard Gomes
@frgomes
Hello, is there a better way to write this endpoint below?
In a nutshell, I'm transforming an IO[Output[Something]] into a Future by calling unsafeToFuture. Since I had already and IO[...], I suppose this call to unsafeToFuture is not necessary, if not undesirable.
Is there a better way to do it, please?
  val productsQuery: Endpoint[IO, ProductListResponse] =
    post( "products" :: jsonBody[SimpleRequest] ) { req: SimpleRequest =>
          val origin = "austria"
          val products: IO[Output[ProductListResponse]] =
            productCache
              .flatMap { cache => cache.ref.get(origin) }
              .map { r => Ok(ProductListResponse(ctx.api.version, None, r.get.contents)) }
          products.unsafeToFuture
    } handle {
      case e: IllegalArgumentException => handleProductList.BadRequest(e)
      case e: Exception                => handleProductList.InternalServerError(e)
    }
Prabhat Kashyap
@PKOfficial
This message was deleted
Sergey Kolbasov
@sergeykolbasov
@frgomes just return IO[Output[Something]] from your endpoint. At the moment you have a round-trip of IO -> Future -> IO
Richard Gomes
@frgomes
@sergeykolbasov : yeah... I suppose I'm missing some import of implicit conversions or something else, since the compiler complains that a Future is required.
[error] /home/rgomes/workspace/guided-repair-api/service/src/main/scala/Endpoints.scala:143:17: type mismatch;
[error]  found   : cats.effect.IO[io.finch.Output[api.model.ProductListResponse]]
[error]  required: scala.concurrent.Future[?]
[error]                 products //XXX .unsafeToFuture //FIXME: investigate if there's a way to avoid this call
I'm using these imports below:
  // These are magic imports which must survive IntelliJ attempts to "help us".
  // @formatter: off
  import cats.effect._
  import cats.implicits._
  import cats.syntax.apply._
  import io.circe.generic.auto._
  import io.finch._
  import io.finch.circe._
  // @formatter: on
Richard Gomes
@frgomes
My mistake. A for comprehension around the error line was imposing a Future. Fixing that fixes the entire endpoint.
@sergeykolbasov Thanks a lot :-)
Richard Gomes
@frgomes
Hello, I'm using filters in my endpoints.
I would like to "inject" a certain MyApp object into the Request when the request is authorized.
At the moment, the auth filter only blocks not authorized requests, but does not pass MyApp to compiled(req).
Any idea how this could be done, please?
trait Filters extends Whiteboard with StrictLogging {
  import io.finch._
  import cats.effect.IO
  import cats.implicits._
  import com.twitter.finagle.http.Status
  import com.twitter.finagle.http.Response

  def authorized(authorization: Option[String]): IO[MyApp] = tokenValidation.authorized(authorization)

  val auth: Endpoint.Compiled[IO] => Endpoint.Compiled[IO] =
    compiled => {
      Endpoint.Compiled[IO] { req =>
        authorized(req.authorization)
          .redeemWith(
            _ => (Trace.empty -> Right(Response(Status.Unauthorized))).pure[IO],
            //FIXME: should pass MyApp object into the request
            // See examples 2 and 3 of: https://finagle.github.io/finch/cookbook.html#defining-custom-endpoints
            myapp => IO(println(myapp)) *> compiled(req))
      }
    }
...
}
Sergey Kolbasov
@sergeykolbasov

@frgomes quick and dirty way would be to use Request#ctx: https://twitter.github.io/finatra/user-guide/http/filters.html#using-c-t-finagle-http-request-ctx or Context from Finagle that is roughly the same as ThreadLocal (but actually request local)

IMO, proper "functional" way would be to use a different monad instead and have an auth that would have a similar signature:

val auth: Endpoint.Compiled[ReaderT[IO, MyApp, *]] => Endpoint.Compiled[IO]

The idea here is to have underlying endpoints with effect ReaderT[IO, MyApp, *] that runs inside of Endpoint.Compiled[IO] where you have an access to request and can build the instance of MyApp

Having a ReaderT as your effect monad allows you to access environment MyApp whenever you feel like it
Richard Gomes
@frgomes
@sergeykolbasov : Thanks a lot. I'm going to try the "proper functional way" with Finch.
Richard Gomes
@frgomes
Integraton with Matrix: any idea why I see twitter/finagle from a Matrix client but I cannot see finagle/finch (this room)?
javier322
@javier322
Hello, how can I build asynchronous rest api with finch? ( I am new with this library)
Ryan Plessner
@rpless
Hi @javier322. If you are using any of the Endpoint Mappers that use Future or IO those are asynchronous. as for making an api RESTful that's really up to you to design the endpoints that way. Finch has all the building blocks for it. The Todo App Example might give you some ideas https://github.com/finagle/finch/blob/master/examples/src/main/scala/io/finch/todo/App.scala
javier322
@javier322
Thanks! @rpless
javier322
@javier322
Are there any example with future?
Sergey Kolbasov
@sergeykolbasov
It's not any different from the non-future examples, except that effect type of endpoint can't be Future and should be some lawful one like IO or Task
Finch will take care of the rest of the machinery
Dermot Haughey
@hderms
@sergeykolbasov doesn't scala/twitter future work do to ToAsync instances being defined for them?
we haven't had issues with it ourselves
Sergey Kolbasov
@sergeykolbasov
Exactly. Although, it's just to lift Future into F[_] : Async therefore you still can't have Endpoint[Future, A]
Dermot Haughey
@hderms
ah yeah
there definitely is a subtle distinction there worth calling out