Let’s build a Free app (neither free as in freedom, nor free as in free beer)

By app I mean full-blown akka-http, slick, cats system with tests. Obviously we’ll keep it simple, but without skipping any important details. If you want to play with the code on your own, you can get it from GitHub. Let’s say this app will be everyone’s favorite Wombat Cuddler Job App — an app for applying for a Wombat Cuddler position on Flinders Island (and no, we didn’t build an app like that. Shame).

So let’s start with a simple template, as we usually do — the entry point to our application.

… And now what? Well, our advice is this:

If you want to build your app around Free, you should start with use-cases — business logic, if you will — and turn these into ADT that you will later write interpreters for.

Forget about services, repositories, and routers. You need to build your language on which you will add all the infrastructure a modern app is going to need.

So, having said that, what’s our use case? Obviously, we need to handle job applicants who are dying to apply for this dream job. Now, we really want a systematic app organization, so let’s go with, say, com.theiterators.wombatcuddler.actions — the package where you’ll keep your functional gems. Let’s start simple and abstract at the same time: by creating Cuddlers trait where we’ll be describing actions that a (prospective) cuddler can perform. We want to register applications from wannabe cuddlers, preferably by accepting some form of request with all the needed bits, validate if this is a unique application (otherwise everyone would be flooding you with their requests), save it to some sort of storage and return, say, a public identifier known only to the one who’s just applied with which he can update his application later on, etc. Easy enough, but we really have to express this “action” by combination of primitive “instructions” (that is, case classes) representing our DSL. That is why we need to form a base language and then write a program in that language (for now, not worrying about the interpretation).

Validations are static things — they take a request and return something along the lines of Either[Error, Request] , so we may want to keep them as simple methods.

What we need to abstract out are operations that we do not yet know how to execute (that will be the job of interpreter) — save request, update request, possibly remove request (if someone is insane enough to resign). Let’s see what it looks like: