Sample Book Catalog REST(ful) web service in Scala with the Spray framework.
API testing will be carried out with JUnit.
Spray is a pattern-matching Routing plug-in for Scala's Akka framework.
It seems very similiar to Python's Flask framework, or Golang's GorillaMux, or even node.js handlers.
It has its own DSL (Domain-Specific Language) for pattern-matching HTTP requests.
Swagger describes itself as the world's most popular API tooling.
The REST API will be documented with Swagger. The very useful Swagger UI rivals Postman.
As far as I can tell Swagger introspects on code annotations, albeit in a very useful way.
Scala features the sbt (Simple Build Tool). At first blush this seems to be yet another build/compile/test/run tool along the lines of make or ant or maven or gradle. But really it is much more along the lines of create-react-app in that it doesn't only download dependencies, it also creates a project directory. And of course it is anything but simple. On the plus side, it does at least enforce a standard project directory structure.
sbt
....
> compile
....
> test
....
> run
....
> exit
$
Or simply:
$ sbt run
As usual, Ctrl-C to terminate.
https://localhost:9001/
As the course material suggests, the Swagger UI is really great (and possibly the best thing about Swagger).
Neither of these browsers will accept self-signed certificates unprompted. To use Firefox it will be necessary to add a security exception (which should be removed later). As Chromium will allow an easy override to proceed to the website anyway, it is probably the browser to use. This only saves a click or two but as it is one less thing to remember about, a useful saving. Also, Chromium will be very clear that the site is untrusted:
For expired certificates (surprisingly common these days) the procedure is much the same.
The HTTPS endpoints may also be verified with either cURL or httpie (first and second options below).
Although httpie is less verbose and has a somewhat more sensible call sequence, my preference is for curl simply because of the -k option (which allows for the ignoring of expired or self-signed security certificates - a bad practice to be sure, but acceptable for testing).
-
with a certificate provided
curl --cacert certificate.crt -vi https://localhost:9001/api/v1/books http --verify=certificate.crt https://localhost:9001/api/v1/books
-
without a certificate provided
curl -vik https://localhost:9001/api/v1/books http --verify=no https://localhost:9001/api/v1/books
-
Search for a book on Google Books:
curl -vik https://localhost:9001/api/v1/search?query=scala
-
Get all books:
curl -vik https://localhost:9001/api/v1/books
-
Get book by ISBN:
curl -vik https://localhost:9001/api/v1/books/978-1935182757
-
Update book by ISBN:
curl -vik -X PUT https://localhost:9001/api/v1/books/978-1935182757 -H "Content-Type: application/json" -d '{"author": "Thomas Alexandre", "title": "Scala for Java Developers", "publishingDate": "2016-12-12"}' -u admin:passw0rd
-
Remove book from the catalog by ISBN:
curl -vik -X DELETE https://localhost:9001/api/v1/books/978-1935182757 -u admin:passw0rd
-
Get all publishers:
curl -vik https://localhost:9001/api/v1/publishers
-
Add new publisher to book catalog:
curl -vik -X POST https://localhost:9001/api/v1/publishers -H "Content-Type: application/json" -d '{"name": "Leanpub"}' -u admin:passw0rd
-
Get publisher by publisher identifier:
curl -vik https://localhost:9001/api/v1/publishers/1
-
Update publisher by publisher identifier:
curl -vik -X PUT https://localhost:9001/api/v1/publishers/1 -H "Content-Type: application/json" -d '{"name": "Leanpub"}' -u admin:passw0rd
-
Remove publisher by publisher identifier:
curl -vik -X DELETE https://localhost:9001/api/v1/publishers/1 -u admin:passw0rd
-
Get all books published by the publisher:
curl -vik https://localhost:9001/api/v1/publishers/1/books
-
Add new book published by the publisher:
curl -vik -X POST https://localhost:9001/api/v1/publishers/2/books -H "Content-Type: application/json" -d '{"isbn": "978-1935182757", "author": "Thomas Alexandre", "title": "Aaa", "publishingDate": "2016-12-12"}' -u admin:passw0rd
In order to use TLS we will need to create an x509 security certificate, along with infrastructure to house it.
By default, openssl will generate unable to write 'random state'
messages if it is unable to write to the user's .rand file (which is normally owned by root). There are a number of work-arounds but the simplest one is to tell openssl to use a different file (this avoids having to obtain root permission):
$ export RANDFILE=./.randfile
This file does not even need to be created, as openssl will create it itself if it cannot find it.
-
Generate .key and .crt files:
$ openssl req -x509 \ -sha256 \ -newkey rsa:2048 \ -keyout certificate.key \ -out certificate.crt \ -days 365 -nodes
-
Export our keys into a PKCS12 keystore:
$ openssl pkcs12 -export \ -in certificate.crt \ -inkey certificate.key \ -out server.p12 \ -name spray-book-catalog \ -password pass:passw0rd
-
Optionally, convert to PEM:
$ openssl x509 -inform PEM -in certificate.crt > certificate.pem
-
Import the certificate into JKS:
$ keytool -importkeystore \ -srcstorepass passw0rd \ -destkeystore spray-book-catalog.jks \ -deststorepass passw0rd \ -srckeystore server.p12 \ -srcstoretype PKCS12 \ -alias spray-book-catalog
PKCS12 keystores offer some improvements over JKS keystores (with Java 9 java keystores use PKCS12 rather than JKS however there may be interoperability problems due to Java's multi-keystore implementation. So it is probably a good idea to retain the original server.p12 keystore in case of compatibility issues).
A PKCS12 keystore usually has a file extension of p12 or pfx.
If desired, the temporary random file may be deleted:
$ rm ./.randfile
Of course, leaving this file in the directory may be a good reminder for the next time.
- Investigate using self-signed certificates with Firefox and Chromium
- Investigate whether both PKCS12 and JKS keystores are really needed
- Investigate replacing openssl / keytool certificate process with cfssl
- Investigate the latest crypto protocols with a view towards certificate generation
- Investigate the failing tests and fix them
- Investigate upgrading to HTTP2
This was the material for the course "Learning Scala Web Development", which can be found here:
https://www.lynda.com/Scala-tutorials/Learning-Scala-Web-Development/521233-2.html
The course was originally published here:
https://www.packtpub.com/web-development/learning-scala-web-development-video
Although the course is only slightly more than a year old, the material has aged. For instance the Spray framework is now apparently deprecated and has been replaced by Akka HTTP. Happily there is a migration guide:
http://doc.akka.io/docs/akka-http/current/scala/http/migration-guide/migration-from-spray.html
The course itself was slightly frustrating - for instance, a good editor would have insisted on idiomatic English. The material itself referred in large part to this code and was more in line with an explanation of the code rather than an actual tutorial. The script was beautifully read by a professional reader, but obviously NOT a subject-matter expert - which made for a slightly jarring experience. Even so, I learned a few things and the editorial comments were interesting.