Skip to content

Instantly share code, notes, and snippets.

@rodrigopr
Last active August 29, 2015 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rodrigopr/ee2a190286ac9949ac5d to your computer and use it in GitHub Desktop.
Save rodrigopr/ee2a190286ac9949ac5d to your computer and use it in GitHub Desktop.

Instead of using TurnJsonIntoHttp in each place:

class MyEndpoint extends Endpoint[HttpRequest, HttpResponse] {
  def route = {
    case Method.Get -> Root / "items" 
      List() ! TurnJsonIntoHttp[List[MyObj]]

    case Method.Get -> Root / "item" / Long(id) 
      GetDetail(id) ! TurnJsonIntoHttp[MyObj]
    
    //...
  }
}

==========

We could do something like:

implicit class ToJsonOps[Req, Resp](service: Service[Req, Resp]) {
  def asJson(implicit encode: EncodeJson[Resp]) =
    new Service[Req, HttpResponse] {
      def apply(req: Req) = service(req) flatMap TurnJsonIntoHttp[Resp]
    }
}

And in route:

class MyEndpoint extends Endpoint[HttpRequest, HttpResponse] {
  def route = {
    case Method.Get -> Root / "items"  
      List().asJson

    case Method.Get -> Root / "item" / Long(id)  
      GetDetail(id).asJson
    
    //...
  }
}
@vkostyukov
Copy link

Like it!

But, instead of writing TurnJsonIntoHttp each time, you can have JSON endpoints, like Endpoint[HttpRequest, Json]. And then endpoint ! TurnJsonIntHttp[???].

I see the point. You expose you model as simple case classes (and lists over case classes). So, you don't use an JSON backend explicitly and just converts pure object to JSON strings?

@rodrigopr
Copy link
Author

Yes @vkostyukov, that's the case.

Before 0.2 I was using like you said:

class MyEndpoint extends Endpoint[HttpRequest, Json] {
  def route = {
    case Method.Get -> Root / "item" / Long(id)  
      GetDetail(id) ! TurnModelIntoJson

With the new implicit encoder/decoder I haven't found a reason to keep the endpoint returning Json (which in my case was a simple String).

@vkostyukov
Copy link

Right. I see the point.

Since, you don't have this intermediate JSON AST layer, you probably don't need endpoints returning the JSON type. You can do HTTP straightforward. So, you have implicit decoders for MyObj and List[MyObj] types that convert them to JSON string. But, can we do better here? What about to have an implicit function def jsonToHttp(...) converting a Service[HttpRequest, A] in Service[HttpRequest, HttpResponse] having an implicit decoder imported. It's almost the same that you suggested, but w/o call to asJson.

We would have something like this:

class MyEndpoint extends Endpoint[HttpRequest, HttpResponse] {
  def route = {
    case Method.Get -> Root / "items"  List.empty[MyObj]
    case Method.Get -> Root / "item" / Long(id)  GetDetail(id)
  }
}

@rodrigopr
Copy link
Author

I tried make the implicit jsonToHttp (that also have an implicit EncodeJson), but it didn't work.
Maybe I did something wrong, gonna try again later and submit a PR with the working solution.

Also, I think that EncodeJson should be contravariant, and likewise, DecodeJson should be covariant.
I'll making few tests, and probably submit another PR with this change.

@vkostyukov
Copy link

Sure! Please go ahead with submitting those two PR. Looking forward to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment