A reservation booking service, made with <3 by BugBusters.
Faustina Cheng, Youngseo Lee, Peter Ma, Shreya Somayajula, & Patrick Tong
See Cricket Care, a demoable client that uses our BugYourSpot service.
The client app, Cricket Care, is a web application used by hospital employees to schedule and manage medical appointments. It makes API calls to our BugYourSpot service to customize what fields they want to store and what datatypes those fields should be. API calls to our service also create/fetch/update/delete appointments. Hospital employees interact with the client app through the front end of the web app, by inputing relevant data into forms.
Previously, users might be constrained with the kind of data they can store in a booking service such as ours. But with BugYourSpot, we allow flexibility by letting their schema be customized, while still providing the foundational booking service. Additionally, the service also performs certain error checks such as checking that times are within their allowable time range, if the time slot has already been booked, and the required fields are being passed in and in the right format, etc.
Use Maven to build/run client app, which can then be accessed at localhost:8080/greeting
.
More information about CricketCare in the README of the CricketCare repo.
API Description and Workflow:
BugYourSpot's structure derives from Spring Boot Flow Architecture examples, which provide several layers of abstraction between the client and the service itself. The client, which is any business that would need to employ some reservation schedule—restaurants, hospitals, the DMV, and more—can make use of several API endpoints to send certain requests. The parameterized information that the client sends is then parsed and gradually propagated throughout the various layers, with various elements of error checking occurring at different levels.
The ReservationController class acts as the first level of interaction with the client, using @PostMapping
, @GetMapping
, @DeleteMapping
, and @GetMapping
annotations to define several endpoints that the client will connect to. The first endpoint that businesses will utilize is the createReservationSchema
, which allows the business to define custom fields that are relevant to their unique customers. For instance, restaurants may elect for a field such as "occasion" to indicate something like an anniversary or a birthday celebration. On the other hand, hospitals may designate a field called "doctor" to store which doctor each reservation will be meeting with. The custom schemas are managed on the backend through an Entity-Attribute Value Model; this structure makes use of several individual tables, linking them together through primary keys and allowing for easy field customizability across different clients. Here is a preliminary diagram of our database.
The ReservationService class acts as the next layer of logic, providing the method definitions for functions such as addNewReservation()
, deleteReservation()
, and updateReservation()
. The class initializes an instance of a ReservationRepository
object, which represents the lowest layer connected to the actual database. Through this object, the ReservationService class implements certain exception handling cases such as when the client / business attempts to delete a non-existent reservation.
POST api/v1/reservation/createClient
Description: The client provides certain fields that they want to represent a reservation with. This is in the form of a JSON object. There are a set of required reservation parameters they have to specify (startTime, endTime, slotLength, reservationsPerSlot) as well as a customValues JSON they can pass in for custom fields they want to include for their reservations. The service validates these fields to ensure that it matches the expected format. Once validated, our service will dynamically generate the database schema based on the custom fields and their data types. Thus, this API should be called just once and before all other API calls.
Request Body: JSON object that represents the fields of a reservation
Example Usage:
- Restaurant
{
"customValues": {
"partySize": "INTEGER",
"birthday": "BOOLEAN"
},
"startTime": "09:00:00",
"endTime": "21:00:00",
"slotLength": 30,
"reservationsPerSlot": 2
}
Response: 200 OK and client ID
1
- Hospital
{
"customValues": {
"doctorId": "INTEGER",
"patientNotes": "VARCHAR"
},
"startTime": "06:00:00",
"endTime": "18:00:00",
"slotLength": 60,
"reservationsPerSlot": 1
}
Response: 200 OK and client ID
2
Other possible statuses: 400 Bad Request and relevant error message if endTime is before startTime/required fields are not passed in/in the wrong format
GET api/v1/reservation/getClient?clientId={}
Description: Get the client shema from a registered client ID.
Example Usage: api/v1/reservation/getClient?clientId=1
Response: 200 OK and client information
[
{
"clientId": 1,
"startTime": "06:00:00",
"endTime": "18:00:00",
"slotLength": 60,
"reservationsPerSlot": 1
}
]
POST api/v1/reservation
Description: Create a new reservation.
Request Body: JSON object representing the reservation details.\
- Restaurant
{
"clientId": 1,
"userId": 1,
"startTime": "2023-11-29T14:00:00",
"numSlots": 2,
"customValues": {
"partySize": 4,
"birthday": true
}
}
Response: 200 OK
- Hospital
{
"clientId": 2,
"userId": 1,
"startTime": "2023-11-29T08:00:00",
"numSlots": 1,
"customValues": {
"doctorId": 1,
"patientNotes": "diabetes"
}
}
Response: 200 OK
Other possible statuses: 400 Bad Request with relevant error message for invalid format/missing/extra fields/unavailable booking/booking not within allowed time
Error if client not initialized
PUT api/v1/reservation
Description: Update an existing reservation or time slot.
Usage: Applications can use this endpoint to modify reservation details, such as changing the booking time or updating user information.\
Request Body: JSON with reservationId, and the fields to be updated
Example request:
{
"reservationId": 1,
"updateValues": {
"startTime": "2023-12-07T16:00:00",
"numSlots": 2,
"doctorId": 22,
"patientNotes": "hypothyroidism"
}
}
Response: 200 OK
Other possible statuses: 400 Bad Request with relevant error message for invalid format/missing/extra fields/unavailable booking/booking not within allowed time/reservation Id doesn't exist
DELETE api/v1/reservation?reservationId={}
Description: Delete a reservation or time slot given a path variable.
Usage: Applications can call this endpoint to remove a reservation when it's no longer needed or has been canceled.
Request Body: None
Example request: api/v1/reservation?reservationId=1
1
Response: 200 OK
Possible statuses: 400 Bad Request with relevant error message if reservation Id doesn't exist
GET api/v1/reservation/getClientReservations?clientId={}
Description: Retrieve a list of all reservations made by a client.
Query Parameters: clientId
Our service will return all reservations made by the client – represented as a simple JSON object with a list of reservation objects.
Example Usage: api/v1/reservation/getClientReservations?clientId=1
Response: 200 OK
- Restaurant
[
{
"birthday": "true",
"numSlots": "2",
"clientId": "1",
"reservationId": "1",
"startTime": "2023-11-29T14:00",
"partySize": "4",
"userId": "1"
},
{
"birthday": "true",
"numSlots": "2",
"clientId": "1",
"reservationId": "2",
"startTime": "2023-11-29T14:00",
"partySize": "4",
"userId": "1"
}
]
Example Usage: /reservations/getClientReservations?clientId=2
Response: 200 OK
- Hospital
[
{
"numSlots": "1",
"patientNotes": "diabetes",
"clientId": "2",
"reservationId": "3",
"doctorId": "1",
"startTime": "2023-11-29T08:00",
"userId": "1"
}
]
Other possible statuses: 400 Bad Request with relevant error message if client Id is not registered
Using JUnit + Mockito framework
-
Unit Tests:
ReservationRepositoryTest.java
ReservationServiceTest.java
ReservationTest.java
ReservationDTOTest.java
ClientDTOTest.java
-
System Tests:
ReservationControllerTest.java
- Mock server-client communication over network (with localhost) using Intellij's HTTP Client Tool
-
Internal Integration Tests:
ServiceIntegrationTest.java
-
External Integration Tests:
ServiceIntegrationTest.java
ConcurrentClientTest.java
ReservationRepositoryTest.java
Additional test documentations are located in the documentation/
folder in the root directory.
- Continuous Integration: CI is set up for the repo such that all build, analysis, and testing tools are automatically run. See report.
- Internal integration: Integration tests are automatically run during CI. See report.
- Branch Coverage: Greater than 85% of branch coverage was achieved. See report.
- Bug Finder: A static analysis bug finder tool is run automatically during CI. See report.
- End-to-end Testing: End-to-end testing of a client was carried out manually and documented.
To set up pre commit hooks for linting:
pip install pre-commit
pre-commit install
Example Style Checker Reports:
- Currently: the PostgreSQL database is being hosted locally. Thus, end-to-end testing of this service can only be done on our local machines. We start up our database, use Maven to build the service, and execute all unit/system tests by manually running them in an IDE.
- Next steps: use Docker to create container for application. From there, our client will be able to run an instance of our program on any machine, since the PostgreSQL database will be hosted on GCP. Further, we will set up a git pre-push hook to automatically run all unit and system tests upon pushing to the repo.
To see code coverage, we used Jacoco
Here are the commands used:
mvn clean test jacoco:report
Then, open ../BugYourSpot/target/site/jacoco/com.example.bugyourspot.reservation/index.html
Here is a screenshot of the coverage, with 91% branch coverage
We setup the Workflow using Github Actions, with the pipeline triggering the build and test after every push.
Here is a screenshot of the Github Actions page with our workflows:
Here are the specific jobs run within the workflow: