This project provides a fast & ultra-lightweight http server (with simpleframework)
with an API dedicated to define server’s routes (request-response), start & stop server.
This works in a Java 6+ environment
The actual project release version is 0.5
Be careful ! Between 0.2 & 0.3 version :
- signature of ServerResponse was change(ServerResponse => StaticServerResponse & DynamicServerResponse). It is not retro-compatible !
- you can’t use String to type your content-type response but fr.simply.util.ContentType builder or some fr.simply.util._ objects
Be careful ! Between 0.3 & 0.4 version :
- 0.4 version works under scala 2.10.x & don’t support 2.9.x version anymore
This project is under test. See test code coverage report here
- custom server’s default response OK
- GET request with params OK
- use * pattern for path route param OK
- check if chosen port was not already used OK
- POST request OK
- cross compilation OK
- push on maven central repository OK
- Dynamic ServerResponse OK
- build in scala 2.10 OK
- Stub Server Fixture Trait OK
- PUT request OK
- HEAD request OK
- DELETE request OK
- OTPIONS, PATCH request OK
- set response headers OK
- Java API TODO
- extends simplyscala-server TODO
simplyscala-server is a SBT project.
It use 0.12 sbt version.
<dependency>
<groupId>com.github.simplyscala</groupId>
<artifactId>simplyscala-server_2.10</artifactId>
<version>0.5</version>
</dependency>
libraryDependencies += "com.github.simplyscala" %% "simplyscala-server" % "0.5"
In your play! project Build file :
object ApplicationBuild extends Build {
val appDependencies = Seq (
"com.github.simplyscala" %% "simplyscala-server" % "0.5"
)
}
You could be tempted to try SNAPSHOT version to test project’s next features.
<project ...>
<repositories>
<repository>
<id>maven snapshot</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
...
<dependency>
<groupId>com.github.simplyscala</groupId>
<artifactId>simplyscala-server_2.10</artifactId>
<version>0.6-SNAPSHOT</version>
</dependency>
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
libraryDependencies += "com.github.simplyscala" %% "simplyscala-server" % "0.6-SNAPSHOT"
In order to use SimplyScala server API, import as follows:
import fr.simply._
val server = new StubServer(8080).start
server.stop
By default, with no routes defined, SimplyScala server returns a 404 text/plain response with “error” in body
You can define your own server’s default response like this :
val server = new StubServer(8080).defaultResponse(ContentType("text/plain"), "value return in body", 400).start
val route = GET (
path = "/test",
params = Map("param1" -> "toto"),
response = StaticServerResponse(ContentType("text/plain"), "yo", 200)
)
val server = new StubServer(8080, route).start
when you request http://localhost:8080/test?param1=toto
, the server returns with an http code 200 and a “text/plain”-typed body containing “yo”.
val route = POST (
path = "/test",
params = Map("param1" -> "toto"),
response = StaticServerResponse(ContentType("text/plain"), "yo", 200)
)
val server = new StubServer(8080, route).start
Since 0.3 version, you able to define some dynamic server response.
To do that, you must define function typed as Request => StaticServerResponse, which permit use some parameters of the
server request to build a response.
import org.simpleframework.http.Request
...
val dynamicResponse: Request => StaticServerResponse = {
request =>
println("I use dynamic code !!!")
StaticServerResponse(Text_Plain, "OK dynamic", 200)
}
val route = GET (
path = "/test",
params = Map("param1" -> "toto"),
response = DynamicServerResponse(dynamicResponse)
)
val server = new StubServer(8080, route).start
Before creating the server instance, SimplyScala checks if the port you defined is not already in use.
If it is the case, SimplyScala will try the next value (+1) port to start the server.
You can retrieve the effective port like this:
val server = new StubServer(8080).start
server.portInUse // perhaps 8081
with fr.simply.util._ import you can use some utilities to declare server’s content type
val route = GET (
path = "/test",
params = Map("param1" -> "toto"),
response = StaticServerResponse(Text_Plain, "yo", 200)
)
val server = new StubServer(8080, route).start
if we don’t have the needed content type util you can use ContentType("your content type")
simplyscala-server is particularly useful in unit test context.
You can use it like that with ScalaTest :
class StubServerTest extends FunSuite {
test("a test which needed simplyscala-server") {
val route = GET (
path = "/test",
params = Map("param" -> "toto"),
response = StaticServerResponse(Text_Plain, "yo", 200)
)
val server = new StubServer(8080, route).start
someHttpRequest("http://localhost:%s/test?param=toto".format(server.portInUse))
}
}
You you do not have to stop the server thanks to when a define port is already used, simplyscala-server start server with next port and return reference to it via portInUse method.
If you want to stop the server & stay immutable, you can use StubServerFixtureTrait like that
import org.scalatest.FunSuite
import fr.simply.{StaticServerResponse, GET}
import fr.simply.util.Text_Plain
import fr.simply.fixture.StubServerFixture
class StubServerFixtureTest extends FunSuite with StubServerFixture {
test("test stub server fixture") {
val route = GET (
path = "/test",
params = Map("param1" -> "toto"),
response = StaticServerResponse(Text_Plain, "yo", 200)
)
withStubServerFixture(8080, route) { server =>
// you can continue your test with server reference
// in this fixture your server stub is started
// at the en d of this fixture your server is stopped
}
}
}
You might need manage server response header, for example in the case of HEAD response.
import org.scalatest.FunSuite
import fr.simply.{StaticServerResponse, HEAD}
import fr.simply.util.Text_Plain
import fr.simply.fixture.StubServerFixture
class StubServerFixtureTest extends FunSuite with StubServerFixture {
test("test stub server fixture") {
val route = HEAD (
path = "/test",
response = StaticServerResponse(Text_Plain, "", 200, Map("headerName" -> "value"))
)
withStubServerFixture(8080, route) { server =>
// the server will have key-value pair "headerName" -> "value" in header response
}
}
}
This file is written with .textile extension