FFC - Fast & Furious Cinema
Backend service for mobile/web application for a small cinema playing only movies from Fast & Furious franchise. Some assumptions were made and some shortcuts were implemented. So be warned that this is just an experimental version.
Build and run
There are some prerequisite to play with the project:
- Docker should be installed - as integration tests are using Testcontainers to avoid all those in-memory/embedded/mocked solutions, and check if integrations really works.
- Docker Compose should be installed - as project is using MongoDB for persistence, and starting provided
docker-copose.yaml
is painless way to run it locally. - OMDb API Key is required - as movie details are fetched from OMDb API.
You can build the service and run all the tests with ./gradlew clean build
. All boilerplate REST API code is generated from OpenAPI specification and all code for mappers is generated from MapStruct annotated interfaces, so if you decide to import this project to IDE of your choice, some missing classes can be reported. Just re-build the project to fix that issues.
If you want to start the application locally, then all you have to do is start all dependencies with:
docker-compose up --detach
And after that start the service with:
ADAPTERS_OMDB_API_KEY=<change-me> ./gradlew bootRun
NOTE: Just remember to use proper API key for OMDb API instead of
<change-me>
. And when you are done playing with the application tear down MongoDB withdocker-compose down --volumes
.
After application is up and running you can explore the API and play with it using:
- Swagger UI available at http://localhost:8080/swagger-ui/
- GraphQL Playground available at http://localhost:8080/graphql-playground/
Some API methods requires you to be authenticated user. You can use one from table below. Mind that STAFF role will allow you to execute methods from internal API.
Username | Password | Roles |
---|---|---|
kermit | secret | STAFF, USER |
elmo | secret | USER |
So simple yet so complicated
I have assumed that cinema that is showing only nine rather mediocre movies will not be operating on daily basis - fixed ticket prices and showing hours. Rather in from event to event manner. And because of that internal API for showing dates and ticket prices looks so simple. Staff member can create an event for a given date with list of screenings and dedicated ticket prices for each of them. Also, that simple PUT for date method could be easily extended to accept POST-ing an ultimate representation of everything - Excel spreadsheet (or at least his simpleton brother CSV file).
One of expected results of the challenge was API documentation in OpenAPI/Swagger format. I have turned that requirement around - I have started with designing specification and using it as an an input for generating REST controllers interfaces and models, and input for validator of incoming requests.
I was trying to design REST API with Richardson's Maturity Model Level 2 in mind, and because of that there are separate resources for showings, movie details and ratings. I hear whining of front-end developers - and now we have to make multiple api calls to get everything what we need. For example to get movie details and its showing hours for given day. Well... you don't have to. As an extra, GraphQL API was implemented, so you can use it to get what you need. Following query result will return movie title, average rating and showing times in a single server call.
{
movieDetails(id: "tt0232500") {
title
averageRating {
averageRating
votesCount
}
showings(from: "2021-12-06", to: "2021-12-12") {
date
showings {
startAt
}
}
}
}
It compiles - deploy
Hell no - there's still a lot to be done. I think that in Fowler's Make It Work - Make It Right - Make It Fast, current state of the service is just after It Work.
At least following should be done:
- Unit tests for all generated mappers, alongside with some programming suggar in form of convenient test data builders/fixtures.
- More fine-grained integration tests - now different scenarios are cramped in one place. Also some "glue" in form of helper methods should be implemented - for example for setting up service state for given scenario.
- Paging in results of API methods returning collections - to avoid returning large payloads and crippling service performance.
- Real security config.
- Real cache implementation and configuration - as one currently used can lead to memory leaks (no restictions on cache size or time), and return inacurate data as OMDb API responses are cached indefinitely.
- Circuit breaker and fallback movie details provider for case when OMDb API would be unavailable.
- API rate limiting and monitoring - to know if service is performant enough and to know when some less naive (non blocking?) implmentation will be required. Not to forget about DoS attacks detection.
- Better exception handling.
- Logging - for now code base is so simple, that I have forgotten about this aspect until now.