Rho + DDD + doobie + Docker scratchpad
My little sandbox for playing around with the FP + OOP + DDD combination, in particular using Rho, doobie, Docker,
integration testing, etc in a project. In the future, this might be spun out into a G8 template.
- Finding that sweet spot between FP, OOP and light DDD
- Get feet wet with using Rho as a routing + API spec layer on http4s through building
not-completely-trivial CRUD API endpoings with one-to-many parent-child modeling
- For booting up app w/ Psql db
- For integration tests
- Migrations tests
- Doobie for interfacing with Postgres
- H2 for simple repository tests
- Using http4s with cats-effect
- Using rho for Swagger support
Chimney for assisting in DDD model transforms between layers
- Using doobie with cats-effect
Pureconfig for loading configuration
Flyway for handling migrations
Docker testkit for bringing up Docker containers on a per-test-suite basis
sbt-native-packager for bundling the app into a Docker image
sbt-docker-compose for bringing up a docker-compose environment based on the main project and a docker-compose.yml file
- Can run the whole project from sbt via
sbt dockerComposeUp (stopped via
- Also used for running Integration tests from a separate subproject
Swagger API spec w/ UI via Webjar
Docker is essential to having fun here, so go download it if you don't have it installed.
Browse the API Spec (Swagger)
sbt dockerComposeUp and go to the root in your browser (e.g. localhost). It will start a
docker-compose environment that includes the web-server and dependencies.
sbt test will run normal tests
sbt dockerComposeTest will run integration tests
- Tying route definition + doc generation together with route implementation is genius. It means the spec is always up
- The type-level mechanism (e.g. that huge HList for capturing status + response types) is amazing. A lot of things
- Multiple branches in your code that respond with different statuses and types get reflected in
the generated docs.
AnyVal wrappers are exposed in the documentation as their underlying type.
- Composing routes + documentation is just by value
- At the "end of the world", you can combine all your Rho service into a single http4s service (currently by calling
.toService and passing in a Rho middle ware). This causes the routes and specs to get compiled.
- This means it's entirely possible to have Rho work along side APIs defined as vanilla http4s endpoints.
- Areas for improvement
- Support for more areas of spec generation
- On models themselves; completely lacking, save for
withCustomSerializer usage (see docs),
which is not optimal (far away from actual models). Would be awesome if it:
- It could be extended (or default to) using Swagger API annotations is they are there.
- Allowed defining the case-ness (e.g. snake or camel)of outputted JSON schema
annotations, for example
- Support more things like endpoint tags and summary (maybe these exist, not sure)
- Documentation is a bit sparse; there's a wiki and some examples ... but that's it.
Integration with Cats standard libs is amazing
- Not being tied to a specific Effect is very liberating (ie working with
F[_] throughout is very clean, no need
implicit eCtx: ExecutionContext boilerplate everywhere)
Comes out of the box with support for various middlewares (auth and there is also tsec,
a crypto lib with an http4s integration module.
Used in production at a number of places, including Verizon, Jack Henry, etc.
Various integrations exist, like
- Various JSON libs like circe, json4s (powered by Jackson or Native), Play-JSON, etc.
http4s itself supports running on various servers other than Blaze (default), including as a Servlet, enabling usage in:
This is interesting because it makes migration easy (mount old Servlets with new ones.)
- This is the real deal for DDD in Scala. Makes DDD so easy and painless.
- Integrates well with the rest of the system due to Cats as lingua franca
- What-you-write-is-what-you-get SQL usage
- JDBC-based so it still blocks a thread somewhere; there is an issue for
a way of emulating Slick3-style asynchronicity
- Safe: type-checked of course, but there are also query soundness checks (see
QuerySoundnessSpec) to check your queries
against a real DB.
- Using docker through the sbt plugin system smooths out integration testing and local manual testing. A boon for lowering
the barrier of entry for devs getting started.
Help me learn ! Ask questions, submit issues and PRs :)