Viper.io is a rapid prototyping toolkit on top of Netty. It's grown from many hackweeks/days and is remarkably easy to use to quickly build HTTP servers:
- Virtual hosting (host multiple domains from the same process)
- container-like jar loading for virtual servers
- serve websites from jar resources (read-only websites, such as splash or product pages)
- easy REST application development (biased towards data-driven clients via JSON)
- SSL server support
- Uploading and downloading of files directly to/from S3 using Netty
- thin layer over Netty making it easy to extend
<dependency>
<groupId>io.viper</groupId>
<artifactId>io.viper.core</artifactId>
<version>0.1.4</version>
</dependency>
Check the examples src for more.
Hello World:
import io.viper.common.{Response, NestServer}
object HelloWorld extends NestServer(9080) {
get("/hello") { args => Response("world") }
}
Static content served from embedded resources:
package io.viper.examples
import io.viper.common.{NestServer, ViperServer}
object StaticHost {
def main(args: Array[String]) {
NestServer.run(8080, new ViperServer("res:///static.com/"))
}
}
Serve files directly to/from S3:
package io.viper.examples.files
import io.viper.common.{ViperServer, NestServer}
import io.viper.core.server.file.HttpChunkProxyHandler
import io.viper.core.server.file.s3.{S3StaticFileServerHandler, S3StandardChunkProxy}
object S3FileServer {
def main(args: Array[String]) {
var awsId = if (args.length > 2) args(0) else "awsId"
var awsKey = if (args.length > 2) args(1) else "awsKey"
var awsBucket = if (args.length > 2) args(2) else "awsBucket"
NestServer.run(8080, new S3FileServer(awsId, awsKey, awsBucket, "localhost"))
}
}
class S3FileServer(awsId: String, awsKey: String, awsBucket: String, downloadHostname: String) extends ViperServer("res:///s3server") {
override def addRoutes {
val proxy = new S3StandardChunkProxy(awsId, awsKey, awsBucket);
val relayListener = new FileUploadChunkRelayEventListener(downloadHostname);
addRoute(new HttpChunkProxyHandler("/u/", proxy, relayListener));
addRoute(new S3StaticFileServerHandler("/d/$path", awsId, awsKey, awsBucket))
}
}
File Server:
package io.viper.examples.files
import io.viper.core.server.file.{StaticFileServerHandler, HttpChunkProxyHandler, FileChunkProxy}
import io.viper.common.{StaticFileContentInfoProviderFactory, ViperServer, NestServer}
object FileServer {
def main(args: Array[String]) {
NestServer.run(9080, new FileServer("/tmp/uploads", "localhost"))
}
}
class FileServer(uploadFileRoot: String, downloadHostname: String) extends ViperServer("res:///fileserver") {
override def addRoutes {
val proxy = new FileChunkProxy(uploadFileRoot)
val relayListener = new FileUploadChunkRelayEventListener(downloadHostname)
addRoute(new HttpChunkProxyHandler("/u/", proxy, relayListener))
val provider = StaticFileContentInfoProviderFactory.create(this.getClass, uploadFileRoot)
get("/d/$path", new StaticFileServerHandler(provider))
}
}
The following shows how two domains can be hosted on port 80. The first, static.com, is a static content site that is hosted from embedded jar resources. The second, rest.com, is a service with REST handlers. This service can easily be expanded to support both static and REST by extending StaticFileServer and adding the REST resources.
package nest.router
import _root_.io.viper.core.server.router._
import io.viper.common.{NestServer, RestServer, StaticFileServer}
import java.util.Map
import org.json.JSONObject
object Main {
def main(args: Array[String]) {
val handler = new HostRouterHandler
// Serve static.com from cached jar resources in the static.com directory
handler.putRoute("static.com", new StaticFileServer("res:///static.com/"))
// Serve REST handlers
handler.putRoute("rest.com", new RestServer {
def addRoutes {
get("/hello", new RouteHandler {
def exec(args: Map[String, String]): RouteResponse = new Utf8Response("world")
})
get("/echo/$something", new RouteHandler {
def exec(args: Map[String, String]): RouteResponse = {
val json = new JSONObject()
json.put("hello", args.get("something"))
new JsonResponse(json)
}
})
}
})
NestServer.run(handler)
}
}
<dependency>
<groupId>io.viper</groupId>
<artifactId>io.viper.core</artifactId>
<version>0.1.4</version>
</dependency>