New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow subclassing of request #116

Closed
capotej opened this Issue Feb 17, 2014 · 2 comments

Comments

3 participants
@capotej
Contributor

capotej commented Feb 17, 2014

Make sure it's possible to subclass a finatra.Request and pass it through the Router.

@labe-me

This comment has been minimized.

labe-me commented Jan 13, 2015

Hello,

I made an attempt and it somehow worked but if another filter do the same the handler will end up with a request proxying a request proxying a request etc and I am not sure how to retrieve the right level containing my data.

Here's my sample in memory session filter. The filter creates a RequestWithSession and pass it to the service.

An implicit is used to retrieve the RequestWithSession from the Request (I had to climb two levels in my test but may be it could end with request.request.request if another filter is involved, I am not sure?).

package com.twitter.finatra_example

import com.twitter.finagle.{ Service, SimpleFilter }
import com.twitter.finagle.http.{Request=>FinagleRequest, Response=>FinagleResponse}
import com.twitter.finatra._
import com.twitter.finagle.http.Cookie

case class Session(
  val id:String
){
  var userId:String = null
}

object Session {
  @inline implicit def autoCast(request:Request) : RequestWithSession = {
    // that's request.request but not sure what would happen if another filter adds a level
    request.request.asInstanceOf[RequestWithSession]
  }
}

class RequestWithSession(request:FinagleRequest, val session:Session) extends Request(request)

class InMemorySessionFilter extends SimpleFilter[FinagleRequest, FinagleResponse]{
  val sessions = collection.mutable.Map[String, Session]()

  def getOrCreateSession(id:String) : Session = {
    sessions.get(id) match {
      case Some(session:Session) => session
      case None => 
        val session = new Session(id)
        sessions.put(id, session)
        session
    }
  }

  def apply(request:FinagleRequest, service:Service[FinagleRequest, FinagleResponse]) = {
    val cookie =  request.cookies.get("_sid_") match {
      case None => new Cookie("_sid_", java.util.UUID.randomUUID().toString)
      case Some(v) => new Cookie("_sid_", v.value)
    }
    val session = getOrCreateSession(cookie.value)
    val requestWithSession = new RequestWithSession(request, session)
    service(requestWithSession) map { response =>
      response.addCookie(cookie)
      response
    }
  }
}

The usage is:

package com.twitter.finatra_example

import com.twitter.finatra._
import com.twitter.finatra.ContentType._
import java.util.concurrent.Executors
import com.twitter.util.FuturePool

// import the implicit Request => RequestWithSession
import Session._

object App extends FinatraServer {

  get("/") { request => 
    println(request.session) // autocasted to RequestWithSession which has a session field
    render.static("index.html") 
  }
  ...
  addFilter(new InMemorySessionFilter)
  register(new ExampleApp())
}

Trying to cast to RequestWithSession and climbing up the hierarchy until it work may be a workaround but it feels wrong :)

I know it's not recommended by Finagle but since a user cannot easily modify the whole framework signature, maybe a request context could do the trick ?

// context as a mutable.HashMap[String, Any] 
request.context += ("SessionAttachmentKey" -> session)
...
// 
request.context("SessionAttachmentKey").asInstanceOf[Session]

I am quite new to finagle and finatra and still a beginner with scala so there must be a nicer way of doing this, any info is very much appreciated :)

Best regards

Laurent

@scosenza

This comment has been minimized.

Contributor

scosenza commented Aug 15, 2015

Subclassing Request is now discouraged in favor of using Request.ctx

@scosenza scosenza closed this Aug 15, 2015

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