Search code examples
scalarestakkafaviconspray

Where to put favicon for a scala Spray application (i.e. what is the root of the site?)?


Internet says I should put my favicon.ico in the root of the site to stop Spray from clogging my logs with huge stacktraces. I don't know what the root of the site means, particularly in the context of a RESTful spray application.

Suppose my project is in ~/src/my-project - I build it (sbt assembly), and run it from this location, where should I put the favicon.ico?? I tried putting in ~/src/my-project but I still get the stacktrace.

NB: it only throws the exception if I directly access the API from my browser (rather than via the actual front end of our website).


Solution

  • Most current browsers are automatically looking for favicon.ico inside your site's root. So, you have to process their GET /favicon.ico http-requests. The easiest way to do that is to use spray-routing's getFromResource:

    import spray.routing.SimpleRoutingApp
    import spray.http._
    import MediaTypes._
    
    object Main extends App with SimpleRoutingApp {
      implicit val system = ActorSystem("my-system")
    
      startServer(interface = "localhost", port = 8080) {
        path("favicon.ico") {
          getFromResource("favicon.ico", `image/x-icon`) // will look for the file inside your `resources` folder
        }
      }
    }
    

    If you already have some processing actor (and don't use spray-routing), you will need to process GET /favicon.ico directly inside your actor, returning something like:

    def receive = {
       case HttpRequest(GET, Uri.Path("/favicon.ico"), _, _, _) => 
          sender ! HttpResponse(entity = HttpEntity(`image/x-icon`, 
             HttpData(new File("favicon.ico")))) //will take it from a file in application folder, you may also pass any array of byte instead of File
       ...
    }
    

    See another answer for more info about second option.

    P.S. If you don't want to bother with favicon.ico file - you may return just StatusCodes.NotFound in both cases:

    • complete(NotFound) for routing
    • sender ! HttpResponse(NotFound) for your own actor

    As it's done inside SiteServiceActor.

    Also, using W3C's preferred method (putting the link inside your web pages) won't guarantee cross-browser compatibility as it depends on the browser's search order and there is no W3C standard about that (see siteData-36). Most browsers seems to look inside the site's root first, even if you don't have any html pages.