📜 ⬆️ ⬇️

We write the simplest REST web service on Scala

I have a website written in Node.js, and sometimes it is necessary to do something there, for which Node.js is not intended : for example, to perform some mathematical calculations.

In this example, we will calculate the password hash.

Let us entrust this work to the “backend” written in a (suitable for computing) functional programming language. For example, on Scala . Functionally, it will be like this: Node.js sends a GET request for hashing to the “backend”, “backend” thinks and thinks, and in response sends the calculated hash in Json format. Normal HTTP request-response, nothing complicated.

Tools


There are many approaches to solving the problem in terms of choosing a set of "frameworks".
')
I wrote a little on Ruby (not on "Rails"), with pleasure using the Sinatra framework. And on Node.js I use a Sinatra clone called Express . It turned out that for Scala the corresponding clone was also written - Scalatra . We will use it.

Popular Rest "frameworks" for Scala


There are also several recognized Scala lightweight Rest “frameworks”:



These “frameworks” were suggested to me by the btd user in the comments. However, I didn’t like any of them - everything is too complicated there, just like in the Scala language itself. I like something simpler ... This is partly why many may be indignant that here I am writing not in Scala, but in Java in the Scala syntax. I do not argue, I prefer Javascript, and Scala just gives me that “function is object” approach, which Java lacked in comparison with Javascript.

How to run this whole thing


If Zen Buddhist, then two files are enough: build.sh of the form “javac -d classes *.java; scalac -classpath […] -d classes *.scala” “javac -d classes *.java; scalac -classpath […] -d classes *.scala” and run.sh of the form “scala -classpath […] -D=8090 Main” .

However, it is better to use a “collector” to avoid messing with file name masks, and with a long one-line classpath : the correct collector (not Maven) will give you much more freedom (and readability) than the shell. He downloads all the used libraries for you himself, and he himself adds each Jar's name to the classpath (and you won't have to do it with your hands).

We will take the young collector (version 1.0 is about to come out) and the developing project Gradle , which reminds me more of the good old Ant , rather than Maven, in that it doesn’t lock the developer into a rigid framework, but rather gives complete creative freedom, and even in the adequate Groovy language (a Ruby clone in the world of Java).

Installation


We put JDK . Checking: java -version

* You may also need to set the JAVA_HOME system variable on the folder with the JDK, and set the bin in the PATH.

We swing Scala , and we register bin in PATH . Checking: scala –version

We swing Gradle , and we register bin in PATH . Checking: gradle –v

Project



The project itself is located on github'e . Here I will give the code of the three main files.

Build Instructions for Gradle - build.gradle

 //   Scala apply plugin: 'scala' ext.scala_version = '2.9.1' ext.jersey_version = '1.12' ext.description = 'Accessing various calculation tasks' //   —   - //   «compileJava»  «compileScala»,      task go(dependsOn: ['compileJava', 'compileScala'], type: JavaExec) { main = 'Main' classpath = sourceSets.main.runtimeClasspath standardInput = System.in systemProperty 'package', 'web' systemProperty 'port', '8090' } //    sourceSets { //  main { java { //      «sources» srcDir 'sources' } scala { //  Scala    «sources» srcDir 'sources' } } } //      «classes» sourceSets.main.output.classesDir = 'classes' //   dependencies { //     Scala  Gradle scalaTools group: 'org.scala-lang', name: 'scala-compiler', version: scala_version scalaTools group: 'org.scala-lang', name: 'scala-library', version: scala_version //  ,    compile group: 'org.scalatra', name: 'scalatra_2.9.1', version: '2.1.0.M1' runtime group: 'org.scalatra', name: 'scalatra_2.9.1', version: '2.1.0.M1' compile group: 'org.mortbay.jetty', name: 'jetty', version: '7.0.0.pre5' runtime group: 'org.mortbay.jetty', name: 'jetty', version: '7.0.0.pre5' compile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' //      jar-   «libraries», //        compile fileTree(dir: 'libraries', include: '*.jar') runtime fileTree(dir: 'libraries', include: '*.jar') } //     repositories { mavenCentral() } 


Now, actually, our REST web-service, which makes it possible to hash a password on Whirlpool or SHA-512 - Hasher.scala

 package web import hash.Whirlpool import hash.SHA class Hasher extends tools.WebService { def path = "/ŃŁ" get("/") { " : Whirlpool, SHA" } get("/Whirlpool/:what") { val  = params("what") json("" -> , "ŃŁ" -> Whirlpool.hash()) } get("/SHA/:what") { val  = params("what") json("" -> , "ŃŁ" -> SHA.hash()) } } 


And I wrote a web server starter (starts all web services from the package package specified in build.gradle) - Main.scala

 import org.mortbay.jetty.Server import org.mortbay.jetty.servlet.{Context, ServletHolder} import tools._ object Main extends App { //  Jetty val server = new Server(System.getProperty("port").toInt) val root = new Context(server, "/", Context.SESSIONS) //      Rest - val package_name : String = System.getProperty("package") //   ScalatraServlet    ( ) ""   . //    "path"  . for (handler <- PackageScanner.getClasses(package_name) if classOf[org.scalatra.ScalatraServlet].isAssignableFrom(handler)) { //      val servlet = handler.newInstance().asInstanceOf[javax.servlet.Servlet] //    ""  try { //     path() val path = handler.getMethod("path").invoke(servlet).toString // ""      Jetty root.addServlet(new ServletHolder(servlet), path + "/*") println(handler.getPackage().getName() + "." + handler.getName() + " is mapped to " + path) } catch { //    path()   case error: NoSuchMethodException => throw new RuntimeException("Method path() not found in class " + handler.getPackage().getName() + "." + handler.getName()) } } //  Jetty server.start() server.join() } 


Run


We download the archive , unpack it, go to the folder and execute the gradle go command. If successful, you will see the launch of the web server in the console:

 gradle go
 : compileJava
 : compileScala
 : processResources UP-TO-DATE
 : classes
 : go
 SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 SLF4J: Defaulting to no-operation (NOP) logger implementation
 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further detail
 > Building>: go


Check


Greeting
Hash our password using the SHA-512 algorithm
Hash our password using the Whirlpool algorithm.

If you have nothing to do (or interesting), you can read more


Scalatra
How to write a build on gradle
Simple REST service on Jersey
About Gradle in Russian
What is Scala and how is it convenient
Unfiltered - a lightweight REST framework for Scala
Spray - Advanced Scala REST Framework
Blue Eyes is also an advanced REST framework for Scala.

Source: https://habr.com/ru/post/143603/


All Articles