Skip to content

A contrived reservation system for interplanetary travel

Notifications You must be signed in to change notification settings

nnicolosi/interplanetary-travel-reservation-system-api-kotlin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

.github/workflows/pipeline.yml Quality Gate Status Lines of Code Coverage

Interplanetary Travel Reservation System API

ganymede.png


Description

This repository contains a Gradle project for a web service API written in Kotlin and leveraging the Spring Boot framework. It uses an H2 database, which can be configured for either the in-memory (default) or the file-based mode of operation.

The project represents a contrived business case, that of an interplanetary travel provider requiring a system for scheduling voyages and booking passage for individual space travellers.


Domain Model

There are only a handful of entities in the domain model, each one described below.

Destination

Destinations represent the planetary bodies (planets and moons) that are available for voyages. They are implemented as an enumeration to simplify the implementation. This approach seems justified due to the fact that they are not expected to change frequently.

Available Destinations
- Callisto
- Europa
- Ganymede
- Io
- Luna
- Mars
- Titan

Spacecraft

Spacecraft represent the vehicles in the company's fleet that are available for voyages. Different spacecraft are certified for different destinations and may have different passenger capacity. They are implemented as an enumeration to simplify the implementation. This approach seems justified due to the fact that they are not expected to change frequently.

Available Spacecraft
- UNS-001 (capacity of 100, certified for Luna only)
- UNS-002 (capacity of 100, certified for Luna only)
- UNS-003 (capacity of 100, certified for Luna only)
- UNS-004 (capacity of 60, certified for Luna and Mars only)
- UNS-005 (capacity of 60, certified for Luna and Mars only)
- UNS-006 (capacity of 60, certified for Luna and Mars only)
- UNS-007 (capacity of 60, certified for Luna and Mars only)
- UNS-008 (capacity of 20, certified for all destinations)
- UNS-009 (capacity of 20, certified for all destinations)
- UNS-010 (capacity of 20, certified for all destinations)

Launchpad

Launchpads are the origin point for any voyage. They are implemented as an enumeration to simplify the implementation. This approach seems justified due to the fact that they are not expected to change frequently.

Available Launchpads
- Launch Pad #1
- Launch Pad #2
- Launch Pad #3

Voyage

Voyages are the central domain entity for the system. They are composed of a spacecraft, a destination, a launchpad, a departure date, and a manifest (of passengers). The system doesn't currently account for return trips, so a voyage effectively "consumes" spacecraft.

Passenger

Passengers are added to the manifest of a voyage. In a more sophisticated system, there would be customers that exist independent of voyages, and each customer would be associated with one or more voyages via a relation entity such as "passage" or " reservation". Perhaps in a future iteration of the system this will be done, but for now this was a convenient way to limit scope.


API Endpoints


Destination


GET: /destination

Returns a JSON array containing all destinations


GET: /destination/{id}

Returns a single destination specified byid (case-insensitive)

JSON Example of a Destination:

{
    "id": "EUROPA",
    "name": "Europa",
    "description": "Slightly smaller than Earth's Moon...",
    "diameter": "3,121 km",
    "gravity": "0.134 g",
    "orbit": "Orbits Jupiter once every 85 hours",
    "rotation": "Tidally locked with Jupiter",
    "day": "85 hours"
}


Spacecraft


GET: /spacecraft

Returns a JSON array containing all spacecraft


GET: /spacecraft/{id}

Returns a single spacecraft specified byid (case-insensitive)

JSON Example of a Spacecraft:

{
  "id": "UNS_008",
  "description": "United Nations Starship, Outer System Fleet",
  "designation": "UNS 008",
  "capacity": 20,
  "destinations": [
    "CALLISTO",
    "EUROPA",
    "GANYMEDE",
    "IO",
    "LUNA",
    "MARS",
    "TITAN"
  ]
}


Launchpad


GET: /launchpad

Returns a JSON array containing all launchpads


GET: /launchpad/{id}

Returns a single launchpad specified byid (case-insensitive)

JSON Example of a Launchpad:

{
  "id": "LP_001",
  "description": "Launch Pad #1",
  "designation": "LP1"
}


Voyage


GET: /voyage

Returns a JSON array containing all voyages


GET: /voyage/{id}

Returns a single voyage specified byid

JSON Example of a Voyage:

{
  "id": 1,
  "spacecraft": {
    "id": "UNS_001",
    "description": "United Nations Starship, Lunar Fleet",
    "designation": "UNS 001",
    "capacity": 100,
    "destinations": [
      "LUNA"
    ]
  },
  "launchpad": {
    "id": "LP_001",
    "description": "Launch Pad #1",
    "designation": "LP1"
  },
  "destination": {
    "id": "LUNA",
    "name": "Luna",
    "description": "Luna is the only moon of Earth...",
    "diameter": "3,475 km",
    "gravity": "0.1654 g",
    "orbit": "Orbits Earth every 708 hours",
    "rotation": "Tidally locked with Earth",
    "day": "708 hours"
  },
  "departure": "2021-03-30T00:00:00.000+00:00"
}

POST: /voyage

Creates a voyage from the JSON request body

JSON Example of a POST Request Body:

{
  "spacecraft": "UNS_001",
  "launchpad": "LP_001",
  "destination": "LUNA",
  "departure": "2021-03-30"
}

Validation Rules:

  • The spacecraft must be available (not reserved for another voyage)
  • The spacecraft must be certified for the destination
  • The launchpad must be available on the departure date
  • The departure date must be in the future

PUT: /voyage

Updates the voyage specified by the id property in the JSON request body

JSON Example of a PUT Request Body:

{
  "id": 1,
  "spacecraft": "UNS_003",
  "launchpad": "LP_001",
  "departure": "2021-03-30"
}

Validation Rules:

  • The spacecraft must be available (not reserved for another voyage)
  • The spacecraft must be certified for the destination
  • The launchpad must be available on the departure date
  • The departure date must be in the future

DELETE: /voyage/{id}

Cancels (deletes) the voyage specified byid

Validation Rules:

  • The manifest must be empty (no passengers)
  • The departure date must be in the future

GET: /voyage/{id}/manifest

Returns a JSON array containing passengers for the voyage

JSON Example of a Voyage Manifest:

[
  {
    "id": 1,
    "firstName": "Nick",
    "lastName": "Nicolosi"
  },
  {
    "id": 2,
    "firstName": "Nicole",
    "lastName": "Nicolosi"
  }
]


Passenger


GET: /passenger/{id}

Returns a single passenger specified byid

JSON Example of a Passenger:

{
  "id": 1,
  "firstName": "Nick",
  "lastName": "Nicolosi",
  "dateOfBirth": "1969-02-05T00:00:00.000+00:00",
  "voyage": {
    "id": 1,
    "spacecraft": {
      "id": "UNS_001",
      "description": "United Nations Starship, Lunar Fleet",
      "designation": "UNS 001",
      "capacity": 100,
      "destinations": [
        "LUNA"
      ]
    },
    "launchpad": {
      "id": "LP_001",
      "description": "Launch Pad #1",
      "designation": "LP1"
    },
    "destination": {
      "id": "LUNA",
      "name": "Luna",
      "description": "Luna is the only moon of Earth, and the fifth largest moon in the Solar System. It is one-quarter the diameter of Earth, making it the largest natural satellite in the Solar System relative to the size of its planet.",
      "diameter": "3,475 km",
      "gravity": "0.1654 g",
      "orbit": "Orbits Earth every 708 hours",
      "rotation": "Tidally locked with Earth",
      "day": "708 hours"
    },
    "departure": "2021-03-30T00:00:00.000+00:00"
  }
}

POST: /passenger

Books passage based on the JSON request body

JSON Example of a POST Request Body:

{
  "voyageId": 1,
  "firstName": "Nick",
  "lastName": "Nicolosi",
  "dateOfBirth": "1969-02-05"
}

Validation Rules:

  • The passenger date of birth must be in the past
  • The departure date must be in the future
  • The spacecraft must have capacity remaining

DELETE: /passenger/{id}

Cancels passage for the passenger specified by id

Validation Rules:

  • The departure date must be in the future


Availability


GET: /availability/spacecraft?destination={destinationId}

Returns a JSON array of available spacecraft, optionally for the given destination

Availability Rules:

  • The spacecraft must be available (not reserved for another voyage)
  • If a destination is specified, the spacecraft must be certified for the destination

GET: /availability/destinations?spacecraft={spacecraftId}

Returns a JSON array of available destinations, optionally for the given spacecraft

Availability Rules:

  • An available spacecraft must be certified for the destination
  • If a spacecraft is specified, that spacecraft must be available and certified for the destination

GET: /availability/launchpads?date={dateString}

Returns a JSON array of available launchpads on the given date (date is required)

Availability Rules:

  • The launchpad must not be reserved for another voyage's departure date

GET: /availability/voyages?destination={destinationId}

Returns a JSON array of available voyages, optionally for the give destination

Availability Rules:

  • The voyage must have a departure date in the future
  • The spacecraft reserved for the voyage must have capacity remaining
  • If a destination is specified, the voyage must have the same destination


Running the Unit Tests

IntelliJ has many affordances for running unit tests. To run the unit tests from the command line, however, enter the following command:

./gradlew clean test


Running the API

Running with Gradle

When running from within IntelliJ, simply run ReservationSystemApplication as you would any Spring Boot application. When running from the command line, navigate to the project root directory and enter the following command:

./gradlew bootRun

With either method, the API should start right up and begin listening on http://localhost:8080

Running with Docker

If you want to run the application in a Docker container (and asssuming you have a Docker host to run the container), start by creating an executable jar. Navigate to the project root directory and enter the following command:

./gradlew bootJar

This should create an executable jar in the /build/libs directory. Next you can build a Docker image by entering the following command:

docker build . -t interplanetary

After the image has been created, you can run the container (exposing the application on port 8080) by entering the following command:

docker run -p 8080:8080 interplanetary

The container should now be running and accessible at http://localhost:8080

Testing the Endpoints

Testing the various endpoints of the API can be done with the Postman transaction collection (format v2.1) included in this repository. Import the collection into your Postman client and use the transactions to perform any of the available API operations.

About

A contrived reservation system for interplanetary travel

Resources

Stars

Watchers

Forks