Serving binary responses

690 views
Skip to first unread message

Yang Zhang

unread,
Aug 24, 2011, 3:53:11 AM8/24/11
to scalat...@googlegroups.com
How do I serve, say, an image/png in Scalatra? I can do:

contentType = "image/png"
response.getOutputStream.write(myByteArray)

but is that the Scalatra way? Thanks.

Ross A. Baker

unread,
Aug 24, 2011, 5:40:35 PM8/24/11
to scalat...@googlegroups.com

If myByteArray is already in memory, that's a good option. If not,
these may be more efficient:

- If it's a File, return that from your action. You get zero-copy
from the default render pipeline.

- You can stream it to avoid materializing the whole PNG into memory:

org.scalatra.util.io.copy(pngStream,response.getOutputStream)

--
Ross A. Baker
ba...@alumni.indiana.edu
Indianapolis, IN, USA

adazz

unread,
Sep 1, 2012, 11:49:51 AM9/1/12
to scalat...@googlegroups.com
Does this still work (2.9.1)? I'm trying to write to the response.getOutputStream and I'm getting, java.lang.NoSuchMethodError: org.scalatra.DynamicScope.response()Lorg/scalatra/Response;


when I try,  org.scalatra.util.io.copy(file.inputStream, response.getOutputStream)

sample code;
get("/imagetest2") {

    val theFile = ms.getTest(); //gets the file (GridFSDBFile) from a my service

    theFile match {
                 case Some(file) => {
                 println("write the new file");
                 contentType = "image/jpg"

                 file.writeTo("c:\\Temp\\myfile4.jpg")        //works but bad idea

                 //org.scalatra.util.io.copy(file.inputStream, response.getOutputStream)  //doesn't work

                  new File("c:\\Temp\\myfile4.jpg")          //works, but just a bad idea

                 }
                 case None => {
                  println ("failed");
                 }
           }

    }

Ivan Porto Carrero

unread,
Sep 1, 2012, 12:47:34 PM9/1/12
to scalat...@googlegroups.com
You don't need to use any of that you can do the following:

get("/imagetest") {
  ms.getTest() map { file =>
    contentType = file.mediaType // i think a gridfs file has a content type attached to it
    file.inputStream
  } getOrElse println("failed")
}

another approach to this is to teach the render pipeline about a gridfsdbfile

class MyServlet extends ScalatraServlet {

   get("imagetest") {  
     ms.getTest
   }

   override def renderPipeline = myOwnDataTypes orElse super.renderPipeline

   def myOwnDataTypes: RenderPipeline = {
      case Some(m: GridFSDBFile) => 
         contentType = m.mediaType
         m.inputStream
   }
}

In the render pipeline you only need to return the next step. 

Extensions like json are also implemented using the render pipeline

Ivan Porto Carrero

unread,
Sep 1, 2012, 12:49:12 PM9/1/12
to scalat...@googlegroups.com
oh you are right the inputstream bit has been removed from the renderpipeline. will add it back and publish a 2.1.1


On Saturday, September 1, 2012 5:49:52 PM UTC+2, adazz wrote:
Reply all
Reply to author
Forward
0 new messages