Welcome to Rent-A-Casum, a simpleton Movie store.
Key features include:
- Database featuring Customers, Users/employees, Movies and Rentals.
- HTTP REST-API end-points.
- Configurable prices rates.
- First-time ever use of DropWizard (v.1.1.0). Personal preference would have been Spring Data Rest, but I wanted to demonstrate quick adoption of an unknown framework, as well as compare it to SDR.
- Based application on the 'dropwizard-example' project, refactored and custom-tailored to suit needs.
The project consists of the following Maven modules:
- rentacasum: parent module.
- rentacasum-domain: JPA/Hibernate based domain entities.
- rentacasum-api: Representations/POJOs used for REST requests/responses.
- rentacasum-service: Hibernate DAOs and business logic service classes.
- rentacasum-application: DropWizard HTTP REST app (Resources, config, security etc.)
- Hierarchy-wise, 'application' sits on top of 'service', which sits on top of 'api' which, finally, sits on top of 'model'
- Main purpose for using multiple modules was separation of concerns.
The following entities are defined (also see adjacent rentacasum_schema.png):
-
Customer
-
Movie
-
Rental
-
User
-
These are, pretty much, self-explanatory. Relationship-wise, only the Rental entity is connected many-to-one to both the Customer and the Movie entities, acting as an 'rich' relationship between them.
-
Each time a customer rents a movie, a rental row is created, containing all charges (initial and extra), as well as renting/return date information and bonus points.
-
Total bonus points for each customers are stored in the customer entity (for easy access), but can also be calculated from the customer's rentals.
- Hibernate/JPA 2.x: Model resides in module 'rentacasum-domain'. Can act as standalone JPA model, since no DropWizard specific dependencies have been included.
- All entites extend a BaseEntity (i.e. via @MappedSuperclass), allowing for easy common field management.
- DAOs can be found under module 'rentacasum-service'.
- Migrations.xml resides under module 'rentacasum-domain'. Liquibase Maven plugin was used generation.
- If future model changes are required, it's as easy as changing the POJOs and running 'mvn liquibase:diff' inside 'rentacasum-domain' (and of course, using the 'db migrate' command on the application itself).
- Database comes pre-loaded with sample Customer, User and Movie data, loaded from 'rentacasum-domain/src/main/resources/init_data.sql' when migrating the db.
- Security is in place, as per the dropwizard-example paradigm, but not used in this application. It is assumed that all operations are performed by a store employee, who already has a right to do pretty much anything.
- A User entity/table has been put in place, containing a single, sample, employee. It's not used in any context right now, but has been put there mainly for future use.
- No views or static HTML assets have been used, the entire applicaiton is a REST API, consuming and serving JSON data.
To test the example application run the following commands.
-
To package the example run the following from the root rentacasum directory.
mvn package
-
Change into the application directory.
cd rentacasum-application
-
To setup the h2 database run.
java -jar target/rentacasum-application-0.0.1-SNAPSHOT.jar db migrate rentacasum.yml
-
To run the server run.
java -jar target/rentacasum-application-0.0.1-SNAPSHOT.jar server rentacasum.yml
- All following POST requests assume a content type of 'application/json', unless otherwise specified. All GET requests return 'application/json'.
- Response statuses for all requests are set, in general, as follows:
- 200: All went ok.
- 400: Something wasn't correct in the request sent.
- 409: Tried to perform an illegal operation (such as re-renting an already rented movie).
- 500: Something went seriously wrong (i.e. database is corrupt).
GET /customers/{customerId}
GET /customers?term=<textual term>&start=<row offset>&rows=<rows to fetch>
Searching is performed in various customer fields.
- 'term' is required, but can be left empty, for a full-field search.
- 'start' and 'rows' default to 0 and 10, respectively, if left empty.
GET /movies?term=<textual term>&onlyAvailable=<true|false>&start=<row offset>&rows=<rows to fetch>
- Searching is performed in various customer fields.
- 'term' is required, but can be left empty, for a full-field search.
- 'onlyAvailable', when set to 'true', fetches only movies NOT rented (defaults to 'false').
- 'start' and 'rows' default to 0 and 10, respectively, if left empty.
POST /rentals
Sample Request body:
{
"customerId": 1,
"movies": [
{
"movie": 1,
"days": 2
},
{
"movie": 3,
"days": 3
},
{
"movie": 5,
"days": 4
}
]
}
- Response includes initial charges, along with bonues points earned.
GET /rentals?customerId=<customerId>
- 'customerId' is required.
- Response includes a list of not-returned rentals
POST /rentals/return
NOTE: "date" is optional, aimed mostly for testing purposes. If not present, "today's" date is used by default.
Sample Request body:
{
"customerId": 1,
"movies": [1,2],
"date": "2017-05-02T00:00:00.000+0000"
}
- Response includes any extra charges applied.