We can use the Spray JSON parser for uses other than a REST API. We add spray-json to our dependencies. Our build.gradle:
apply plugin: 'scala'
version = '1.0'
repositories {
mavenCentral()
}
dependencies {
compile group: 'io.spray', name: 'spray-json_2.11', version: '1.3.1'
}
Continue reading →
Both the JVM and keytool have problems dealing with keystores without a password. If you try to get a listing of the keystore it will think you didn't provide a password and output falsehoods:
$ keytool -list -storetype pkcs12 -keystore keystoreWithoutPassword.p12
Enter keystore password:
***************** WARNING WARNING WARNING *****************
* The integrity of the information stored in your keystore *
* has NOT been verified! In order to verify its integrity, *
* you must provide your keystore password. *
***************** WARNING WARNING WARNING *****************
Keystore type: PKCS12
Keystore provider: SunJSSE
Your keystore contains 1 entry
tammo, Oct 14, 2015, SecretKeyEntry,
Continue reading →
In a previous blog post we made an API with spray. Now we're going to load test it. For this, we will use http://gatling.io/#/. In a scala class we can write exactly what and how we want to run the test. In this test, we will do a post to our API and create a new robot called C3PO. We will do this 1000 times per second and keep doing this for 10 seconds. For a total of 10000 C3POs! RobotsLoadTest.scala:
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
class RobotsLoadTest extends Simulation {
val baseUrl = "http://localhost:8080" //We need to have our API running here
val httpProtocol = http
.baseURL(baseUrl)
.inferHtmlResources()
.acceptEncodingHeader("gzip,deflate")
.contentTypeHeader("application/json")
.userAgentHeader("Apache-HttpClient/4.1.1 (java 1.5)")
val s = scenario("Simulation")
.exec(http("request_0")
.post("/robots")
.body(StringBody("""{
| "name": "C3PO",
| "amountOfArms": 2
|}""".stripMargin))
)
setUp(s.inject(constantUsersPerSec(1000) during(10 seconds))).protocols(httpProtocol)
}
Continue reading →
Suppose I have a List of things on which I want to do something that may fail. In this example I have a List of Strings that I want to turn into a List of Integers.
val strings = List("1", "bla", "4")
Continue reading →
In a previous blog I wrote how to make an API. See here.
Now we'll make a client to use that API. This can be done with spray-client. First we add dependencies for spray-client and spray-json:
apply plugin: 'scala'
version = '1.0'
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.scala-lang', name: 'scala-library', version: '2.11.6'
compile group: 'com.typesafe.akka', name: 'akka-actor_2.11', version: '2.3.9'
compile group: 'com.typesafe.akka', name: 'akka-remote_2.11', version: '2.3.9'
testCompile group: 'org.scalatest', name: 'scalatest_2.11', version: '2.2.4'
compile group: 'io.spray', name: 'spray-http_2.11', version: '1.3.3'
compile group: 'io.spray', name: 'spray-httpx_2.11', version: '1.3.3'
compile group: 'io.spray', name: 'spray-json_2.11', version: '1.3.1'
compile group: 'io.spray', name: 'spray-client_2.11', version: '1.3.3'
}
Continue reading →
In Spray, you get a lot of input validations for free. If you have a model like this:
object RobotProtocol extends DefaultJsonProtocol {
case class Robot(name: String, amountOfArms: Int)
implicit val RobotFormat = jsonFormat2(Robot)
}
Continue reading →
Scala has no default way to deal with dates and times. We have a few options. java.util.Date and java.util.Calendar These come included with java, so they may do if you don't need to do much and don't want to add any dependencies. But they're horrible and it's best not to use them. Joda-Time http://www.joda.org/joda-time/ The de facto standard date and time library for Java. nscala-time https://github.com/nscala-time/nscala-time A thin scala layer around Joda-Time. This adds some implicit conversions to make it easier to use, like the + and < operators.
import com.github.nscala_time.time.Imports._
DateTime.now + 2.months // returns org.joda.time.DateTime
Continue reading →
On a server you may want to deploy your application as a war. How to build a war with spray-servlet Locally it's easiest to run without an application server. We include both the spray-servlet and spray-can dependencies:
name := "sprayApiExample"
version := "1.0"
scalaVersion := "2.11.6"
libraryDependencies ++= {
val akkaV = "2.3.9"
val sprayV = "1.3.3"
Seq(
"io.spray" %% "spray-can" % sprayV,
"io.spray" %% "spray-servlet" % sprayV,
"io.spray" %% "spray-routing" % sprayV,
"io.spray" %% "spray-json" % "1.3.1", //has not been updated yet
"com.typesafe.akka" %% "akka-actor" % akkaV
)
}
//This adds tomcat dependencies, you can also use jetty()
tomcat()
Continue reading →
We will use spray-servlet to build a war file of our API. So we can run it in a java app server. I assume we already have a working REST API. We will need a web.xml, under src/main/webapp/WEB-INF/:
spray.servlet.Initializer
SprayConnectorServlet
spray.servlet.Servlet30ConnectorServlet
true
SprayConnectorServlet
/*
Continue reading →
Suppose I want to make coffee. This involves 4 steps:
- 1a. grind coffee beans
- 1b. heat water
- combine
- filter
Continue reading →
Building a rest API with akka and spray is easy. This is how I did it: SprayApiApp:
import akka.actor.{ActorSystem, Props}
import akka.io.IO
import akka.pattern.ask
import akka.util.Timeout
import spray.can.Http
import scala.concurrent.duration._
object SprayApiApp extends App {
//we need an ActorSystem to host our application in
implicit val system = ActorSystem("SprayApiApp")
//create apiActor
val apiActor = system.actorOf(Props[ApiActor], "apiActor")
//timeout needs to be set as an implicit val for the ask method (?)
implicit val timeout = Timeout(5.seconds)
//start a new HTTP server on port 8080 with apiActor as the handler
IO(Http) ? Http.Bind(apiActor, interface = "localhost", port = 8080)
}
ApiActor:
import akka.actor.{ActorLogging, Actor}
import spray.http.MediaTypes
import spray.httpx.SprayJsonSupport._
import spray.json.DefaultJsonProtocol
import spray.routing._
object RobotProtocol extends DefaultJsonProtocol {
//Our domain class
case class Robot(name: String)
//We use the default json marshalling for Robot.
//There are multiple jsonFormat methods in DefaultJsonProtocol. Depending on how many parameters the model class has.
//Robot has just one, so we use jsonFormat1
implicit val RobotFormat = jsonFormat1(Robot)
}
import RobotProtocol._
class ApiActor extends Actor with HttpService with ActorLogging {
//A list of our domain objects
var robots = List(Robot("R2D2"), Robot("Asimo"))
//The HttpService trait defines only one abstract member, which
//connects the services environment to the enclosing actor or test
def actorRefFactory = context
//This actor only runs our route, but you could add
//other things here, like request stream processing or timeout handling
def receive = runRoute(apiRoute)
//Notice that both path methods return a Route. We need to chain them together with ~
val apiRoute: Route =
path("robots") {
get { //with get we will return our current list of robots
log.info("Building get route")
complete {
log.info("Executing get route")
//complete will return the result in an appropriate format
//With SprayJsonSupport it knows how to marshall a List to json
//With RobotFormat it knows how to marshall Robot
robots
}
} ~ post { //With post we will add a robot
log.info("Building post route")
handleWith { robot: Robot => //handleWith will unmarshall the input
log.info("Executing post route")
robots = robot :: robots
robot //handleWith will also marshall the result. Here we simply return the new robot.
}
}
} ~ path("") { //When we go to localhost:8080/ just show a link to localhost:8080/robots
respondWithMediaType(MediaTypes.`text/html`) { //XML is marshalled to `text/xml` by default, so we simply override here
complete {
[The list of robots](/robots)
}
}
}
}
Continue reading →
When you start using Scala, it's tempting to also start using sbt. You can also use your favorite build tool: Gradle. This is my default Gradle build file:
apply plugin: 'scala'
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.scala-lang', name: 'scala-library', version: '2.11.5'
compile group: 'com.typesafe.akka', name: 'akka-actor_2.11', version: '2.3.9'
compile group: 'com.typesafe.akka', name: 'akka-remote_2.11', version: '2.3.9'
testCompile group: 'org.scalatest', name: 'scalatest_2.11', version: '2.2.4'
}
//run the akka application
task run(type: JavaExec, dependsOn: classes) {
//object to run. (The one that extends App)
main = 'pi.Pi'
classpath sourceSets.main.runtimeClasspath
classpath configurations.runtime
}
//run scala tests. These are not automatically picked up by gradle,
//so we run them like this.
task spec(dependsOn: ['testClasses'], type: JavaExec) {
main = 'org.scalatest.tools.Runner'
args = ['-R', 'build/classes/test', '-o']
classpath = sourceSets.test.runtimeClasspath
}
Continue reading →