- Search movie titles + cast crew
- Search top-rated movies for a genre
- Kevin Bacon Number
Purely Function Scala app to search movies by title, find top rated movies for a genre and get Bacon Number for a celebrity. Uses Typelevel scala fp ecosystem cats, cats-effect, http4s, circe, skunk and scala 3 with Tagless-Final encoding.
- Docker (with Docker Compose v2)
- SBT (for building/running the app)
- (optional) Make (for Makefile commands)
- Java 21+ JDK (e.g. Adoptium Temurin)
make db-init(first-time Postgres + IMDb data loader)make run(starts the API server 8080 on localhost)curl -s "http://127.0.0.1:8080/v1/kevinBaconNumber/Jon%20Hamm?maxPaths=2"(to test the API)
This project uses a Postgres container(arm64v8/postgres:18.1-alpine.) plus a one-shot IMDb loader
docker compose up -dstarts only Postgres on port 5432 (fast; no loader runs).
Or using the Makefile:
make docker-up
Run the loader explicitly via the init profile:
docker compose --profile init up -d --build postgres-init
Or:
make db-init
The loader writes a sentinel file into the downloads volume, so future init runs will immediately exit.
To refresh the dataset later, run the update profile:
docker compose --profile update up -d --build postgres-update
Or:
make db-update
The update job caches downloads and only imports when the downloaded .gz content changed.
docker compose downstops containers but keeps the Postgres data + download cache.docker compose down -vdeletes volumes (full reset).
Makefile equivalents:
make docker-downmake docker-reset
Note: profiles require Docker Compose v2 (
docker compose ...). If you only have the legacydocker-composecommand, install/enable Compose v2.
The repo includes a Makefile with common build targets:
make compilemake testmake fmt/make fmt-checkmake lint/make lint-fixmake run(starts the API in foreground)make start(start API with auto-restart on code changes, useBG=1for background)make stop(stop API via sbt-revolver)make restart(restart API with auto-restart on code changes, useBG=1for background)make status(check if API is running)make github-workflow-generate/make github-workflow-check
For fast development turnaround, use sbt-revolver which automatically loads configuration from .env and .jvmopts:
Using Makefile (recommended):
# Watch mode (default) - auto-restart on code changes with live logs
make start # Start with auto-restart enabled (Ctrl-C to stop)
make restart # Restart with auto-restart enabled
make stop # Stop the application
make status # Check if running
# Background mode - app runs detached (use BG=1)
make start BG=1 # Start in background
make restart BG=1 # Restart in backgroundUsing sbt directly:
# First, ensure sbt server is running (run once per session)
sbt
# Then in another terminal, use --client flag:
sbt --client "core/reStart" # Start
sbt --client "core/reStop" # Stop
sbt --client restart # Restart (using alias)
sbt --client "core/reStatus" # Check statusConfiguration files:
.env- Environment variables (SC_APP_ENV, SC_POSTGRES_PASSWORD, etc.).jvmopts- JVM options (memory, GC settings, etc.)
Both files are automatically loaded when using reStart.
-
Set environment variables like described below:
set postgres db_password
export SC_POSTGRES_PASSWORD=postgresto set app environment
export SC_APP_ENV=Test
Build And Run
- Download SBT to build the project
sbt runto start the server on port 8080
[info] running Main
01:50:30.818 [io-compute-3] INFO Main - Loaded config AppConfig(PostgreSQLConfig(localhost,5432,postgres,Secret(afc848c),imdb,10),HttpServerConfig(0.0.0.0,8080))
01:50:31.346 [io-compute-11] INFO Main - Connected to Postgres PostgreSQL 13.3 (Debian 13.3-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
01:50:31.927 [io-compute-2] INFO o.h.ember.server.EmberServerBuilder - Ember-Server service bound to address: /0:0:0:0:0:0:0:0:8080
01:50:31.929 [io-compute-2] INFO Main -
_ _ _ _ _
| |_| |_| |_ _ __| | | ___
| ' \ _| _| '_ \_ _(_-<
|_||_\__|\__| .__/ |_|/__/
|_|
HTTP Server started at /0:0:0:0:0:0:0:0:8080
TroubleShooting
- Make sure there are no error during builds
- Environment variable
SC_POSTGRES_PASSWORDandSC_APP_ENVis set as described above - App tests postgres connection on start so look out for error logs in case of connection failure
Routes
- /GET movieByTitle
/v1/movies/The%20Dark%20Knight%20Rises
{
"movie": {
"movieId": "tt1345836",
"titleType": "movie",
"primaryTitle": "The Dark Knight Rises",
"originalTitle": "The Dark Knight Rises",
"ratedAdult": false,
"yearReleased": 2012,
"yearEnded": null,
"runtimeInMinutes": 164,
"genres": "Action,Adventure"
},
"castAndCrew": [
{
"role": "actor",
"people": [
"Christian Bale",
"Tom Hardy",
"Gary Oldman"
]
},
{
"role": "actress",
"people": [
"Anne Hathaway"
]
},
{
"role": "director",
"people": [
"Christopher Nolan"
]
},
{
"role": "producer",
"people": [
"Emma Thomas",
"Charles Roven"
]
},
{
"role": "writer",
"people": [
"Bob Kane",
"Jonathan Nolan",
"David S. Goyer"
]
}
]
}- /GET moviesByGenre top250
/v1/ratings/dramaor (/v1/ratings/drama?limit=2)
[
{
"movie": {
"movieId": "tt0111161",
"titleType": "movie",
"primaryTitle": "The Shawshank Redemption",
"originalTitle": "The Shawshank Redemption",
"ratedAdult": false,
"yearReleased": 1994,
"yearEnded": null,
"runtimeInMinutes": 142,
"genres": "Drama"
},
"averageRating": 9.3,
"numOfVotes": 2328874
},
{
"movie": {
"movieId": "tt0137523",
"titleType": "movie",
"primaryTitle": "Fight Club",
"originalTitle": "Fight Club",
"ratedAdult": false,
"yearReleased": 1999,
"yearEnded": null,
"runtimeInMinutes": 139,
"genres": "Drama"
},
"averageRating": 8.8,
"numOfVotes": 1844544
}
]- /GET
/v1/kevinBaconNumber/Max%20Schreck?maxPaths=2
{
"baconNumber": 3,
"paths": [
{
"baconNumber": 3,
"path": [
{
"actorName": "Kevin Bacon",
"movieTitle": "The 63rd Annual Golden Globe Awards"
},
{
"actorName": "Candice Bergen",
"movieTitle": "The 50th Annual Directors Guild of America Awards"
},
{
"actorName": "David Carradine",
"movieTitle": "Nosferatu: The First Vampire"
}
]
},
{
"baconNumber": 3,
"path": [
{
"actorName": "Kevin Bacon",
"movieTitle": "The Air Up There"
},
{
"actorName": "Paul Michael Glaser",
"movieTitle": "Jealousy"
},
{
"actorName": "David Carradine",
"movieTitle": "Nosferatu: The First Vampire"
}
]
}
]
}