The following document provides details on the Rate API including definition of the available routes, and design decisions with the architecture of the API.
The following command will build the project and run all the unit tests.
./gradlew clean build
Unit tests can be run through the following command.
./gradlew test
Note: A test report is generated following the test run with the location of the test file being part of the output of the test command.
After building the project, the following command will start the server using the jar file generated by the build command.
java -jar build/libs/rate-api-0.1.0.jar
In to retrieve a rate based on a start date time and end date time the following endpoint is provided
- Example
curl -G -v http://localhost:8081/v1/rate --data-urlencode "startDateTime=2015-07-01T07:00:00-05:00" --data-urlencode "endDateTime=2015-07-01T12:00:00-05:00" - Route -
/v1/rate - Method -
GET - Query Params
startDateTime- the start date and time formatted as aendDateTime- the end date and time formatted as a
- Response Body
{ "price": 1750, "status": "available", "startDateTime": "2015-07-01T07:00-05:00", "endDateTime": "2015-07-01T12:00-05:00" }
Rates can be updated in memory within the API by posting a new set of rates as a JSON body
- Example Request
curl -v -XPOST http://localhost:8081/v1/rate -d ' { "rates": [ { "days": "mon,tues,thurs", "times": "0900-2100", "tz": "America/Chicago", "price": 1500 } ] }' - Route -
/v1/rate - Method -
POST - Request Body
{ "rates": [ { "days": "mon,tues,thurs", "times": "0900-2100", "tz": "America/Chicago", "price": 1500 }, { "days": "fri,sat,sun", "times": "0900-2100", "tz": "America/Chicago", "price": 2000 }, { "days": "wed", "times": "0600-1800", "tz": "America/Chicago", "price": 1750 }, { "days": "mon,wed,sat", "times": "0100-0500", "tz": "America/Chicago", "price": 1000 }, { "days": "sun,tues", "times": "0100-0700", "tz": "America/Chicago", "price": 925 } ] } - Response -
200code if successful,400if a bad request
Metrics for the individual endpoints can be retrieved through a GET requests
- Example Request
curl -v localhost:8081/v1/metrics | jq . - Route -
/v1/metrics - Method -
GET - Response Body
[ { "id": { "name": "http.server.request.latency", "tags": [ { "key": "method", "value": "POST" }, { "key": "path", "value": "v1_rate" }, { "key": "status", "value": "200" } ], "type": "TIMER", "description": "Timing of server requests", "baseUnit": "seconds", "tagsAsIterable": [ { "key": "method", "value": "POST" }, { "key": "path", "value": "v1_rate" }, { "key": "status", "value": "200" } ] } }, ... { "id": { "name": "http.server.request.count", "tags": [ { "key": "method", "value": "GET" }, { "key": "path", "value": "v1_rate" }, { "key": "status", "value": "400" } ], "type": "COUNTER", "description": "Total number of server requests", "baseUnit": null, "tagsAsIterable": [ { "key": "method", "value": "GET" }, { "key": "path", "value": "v1_rate" }, { "key": "status", "value": "400" } ] } }
Documentation can be retrieved from the API through the following request. The swagger documents follow the OpenApi 3.0 format
- Example Request
curl -v localhost:8081/v1/api/swagger.json | jq . - Route -
/v1/api/swagger.json - Method -
GET - Response Body
{ "info": { "title": "Rate API", "version": "v1.0", "description": "This API stores and provides rates for given time ranges." }, "tags": [], ... }
This API is built entirely in Kotlin and uses the http4k library for defining the routes. This library provides several useful features which can be found on the their website linked earlier. For this project the main highlights were the following.
- Immutability given the "Application as Function" design
- Easy documentation since swagger documentation is integrated with the library
- Simple to test using http4k test library
- Easy integration of metrics reporting
I could have easily taken this further to make the underlying rates immutable by adding in a process to version the rates when an rate POST request is sent to updat the rates. However, the current state of the project works well as is with the explicit mutable map implementation.
I added a few notes within the [RateDao] on how the rates were stored within the API. The storage of the rates relies heavily on the guava library and specifically the [RangeMap] implementation within that library. This data structure is well suited to problems involving scheduling like the rates API. The time ranges can be stored as keys in the map so then retrieval of the rates can be done in two map lookups.