<groupId>info.ejava.assignments.api.{ASSN_BASE}</groupId>
AutoRentals Assignment 2: API
copyright © 2024 jim stafford (jim.stafford@jhu.edu)
The API assignment is a single assignment that is broken into focus areas that relate 1:1 with the lecture topics. You have the choice to start with any one area and either advance or jump repeatedly between them as you complete the overall solution. However, you are likely going to want to start out with the modules area so that you have some concrete modules to begin your early work. It is always good to be able to perform a successful root level build of all targeted modules before you begin adding detailed dependencies, plugins, and Java code.
1. Overview
The API will include three main concepts. We are going to try to keep the business rules pretty simple at this point:
-
Auto - an individual auto that can be part of an AutoRental
-
Autos can be created, modified, listed, and deleted
-
-
Renter - identification for a person that may be part of a AutoRental and is not specific to any one AutoRental
-
Renters can be created, modified, listed, and deleted
-
-
AutoRental - identifies a specific Auto and Renter agreement for a period of time
-
AutoRentals must be created with an existing auto and renter
-
AutoRentals must be created with a current or future, non-overlapping period of time for the auto
-
AutoRentals must be created with a renter with a minimum age (21)
-
AutoRental time span is modifiable as long as the auto is available
-
AutoRental can be deleted
-
1.1. Grading Emphasis
Grading emphasis is focused on the demonstration of satisfying the listed learning objectives and — except the scenarios listed at the end — not on quantity. Most required capability/testing is focused on demonstration of what you know how to do. You are free to implement as much of the business model as you wish, but treat completing the listed scenarios at the end of the assignment (within the guidance of the stated static requirements) as the minimal functionality required.
1.2. AutoRenter Support
You are given a complete implementation of Auto and Renter as examples and building blocks in order to complete the assignment. Your primary work will be in completing AutoRentals.
1.2.1. AutoRenter Service
The autorenters-support-api-svc
module contains a full @RestController/Service/Repo thread for both Autos and Renters. The module contains two Auto-configuration definitions that will automatically activate and configure the two services within a dependent application.
The following dependency can be added to your service solution to bring in the Autos and Renters service examples to build upon.
<dependency>
<groupId>info.ejava.assignments.api.autorentals</groupId>
<artifactId>autorenters-support-api-svc</artifactId>
<version>${ejava.version}</version>
</dependency>
1.2.2. AutoRenter Client
A client module is supplied that includes the DTOs and client to conveniently communicate with the APIs. Your AutoRental solution will inject the Autos and Renters service components for interaction but your API tests will use the Auto and Renter http-based APIs. For demonstration,
-
the AutoAPIClient is implemented using explicit RestTemplate calls
-
the RenterAPIClient is implemented using Spring 6 Http Interface
The implementation details are available for inspection, but encapsulated such that they work the same via their AutosAPI and RentersAPI.
The following dependency can be added to your solution to bring in the Autos and Renters client artifact examples to build upon.
<dependency>
<artifactId>autorenters-support-api-client</artifactId> (1)
<version>${ejava.version}</version>
</dependency>
1 | dependency on client will bring in both client and dto modules |
1.2.3. AutoRenter Tests
You are also supplied a set of tests that are meant to assist in your early development of the end-to-end capability. You are still encouraged to write your own tests and required to do so in specific sections and for the required scenarios.
You may find it productive and helpful to address the supplied tests first and implement the scenario tests at the end. It is up to you. At any time you can break off and write special-purpose tests for your own purpose. |
The supplied tests are made available to you using the following Maven dependency.
<dependency>
<groupId>info.ejava.assignments.api.autorentals</groupId>
<artifactId>autorenters-support-api-svc</artifactId>
<version>${ejava.version}</version>
<classifier>tests</classifier> (1)
<scope>test</scope>
</dependency>
1 | tests have been packaged within a separate -tests.java |
The provided tests require that:
-
your AutoRental DTO class implement a
RentalDTO
"marker" interface provided by the support module. This interface has nothing defined and is only used to identify your DTO during the tests. -
implement a
ApiTestHelper<T extends RentalDTO>
interface and make it a component available to be injected into the provided tests. A full skeleton of this class implementation has been supplied in the starter. -
supply a
@SpringBootTest
class that pulls in theAutoRentalsApiNTest
test case as a base class from the support module. This test case evaluates your solution during several core steps of the assignment. Much of the skeletal boilerplate for this work is provided in the starter.
Enable the tests whenever you are ready to use them. This can be immediately or at the end.
Groups of Tests can be Disabled Early In Development
There are empty
|
The tests are written to execute from the subclass in your area. With adhoc navigation, sometimes the IDE can get lost — lose the context of the subclass and provide errors as if there were only the base class. If that occurs — make a more direct IDE command to run the subclass to clear the issue. |
2. Assignment 2a: Modules
2.1. Purpose
In this portion of the assignment, you will demonstrate your knowledge of establishing Maven modules for different portions of an application. You will:
-
package your implementation along proper module boundaries
2.2. Overview
In this portion of the assignment you will be establishing your source module(s) for development. Your new work should be spread between two modules:
-
a single client module for DTO and other API artifacts
-
a single application module where the Spring Boot executable JAR is built
Your client module should declare a dependency on the provided autorenters-support-api-client
to be able to make use of any DTO or API constructs.
Your service/App module should declare a dependency on autorenters-support-api-svc
to be able to host the Auto and Renter services.
You do not copy or clone these "support" modules.
Create a Maven dependency on these and use them as delivered.
2.3. Requirements
-
Create your overall project as two (or more) Maven modules under a single parent
-
client module(s) should contain any dependencies required by a client of the Web API. This includes the DTOs, any helpers created to implement the API calls, and unit tests for the DTOs. This module produces a regular Java JAR.
autorenters-support-api-client/dto
has been supplied for you use as an example and be part of your client modules. Create a dependency on the client module for access toAuto
andRenter
client classes. Do not copy/clone the support modules. -
svc module to include your AutoRentals controller, service, and repository work.
autorenters-support-api-svc
has been supplied for you to both be part of your solution and to use as an example. Create a Maven dependency on this support module. Do not copy/clone it. -
app module that contains the
@SpringBootApplication
class will produce a Spring Boot Executable JAR to instantiate the implemented services.The app and svc modules can be the same module. In this dual role, it will contain your AutoRental service solution and also host the @SpringBootApplication
.The Maven pom.xml in the assignment starter for the App builds both a standard library JAR and a separate executable JAR (bootexec) to make sure we retain the ability to offer the AutoRental service as a library to a downstream assignment. By following this approach, you can make this assignment immediately reusable in assignment 3. -
parent module that establishes a common groupId and version for the child modules and delegate build commands. This can be the same parent used for assignments 0 and 1. Only your app and client modules will be children of this parent.
-
-
Define the svc module as a Web Application (dependency on
spring-boot-starter-web
). -
Add a
@SpringBootApplication
class to the app module (already provided in starter for initial demo). -
Once constructed, the modules should be able to
-
build the project from the root level
-
build regular Java JARs for use in downstream modules
-
build a Spring Boot Executable JAR (bootexec) for the
@SpringBootApplication
module -
immediately be able to access the
/api/autos
and/api/renters
resource API when the application is running — because of Auto-Configuration.Example Calls to Autos and Renters Resource API$ curl -X GET http://localhost:8080/api/autos {"contents":[]} $ curl -X GET http://localhost:8080/api/renters {"contents":[]}
-
2.4. Grading
Your solution will be evaluated on:
-
package your implementation along proper module boundaries
-
whether you have divided your solution into separate module boundaries
-
whether you have created appropriate dependencies between modules
-
whether your project builds from the root level module
-
whether you have successfully activated the Auto and Renter API
-
2.5. Additional Details
-
Pick a Maven hierarchical groupId for your modules that is unique to your overall work on this assignment.
3. Assignment 2b: Content
3.1. Purpose
In this portion of the assignment, you will demonstrate your knowledge of designing a Data Transfer Object that is to be marshalled/unmarshalled using various internet content standards. You will:
-
design a set of Data Transfer Objects (DTOs) to render information from and to the service
-
define a Java class content type mappings to customize marshalling/unmarshalling
-
specify content types consumed and produced by a controller
-
specify content types accepted by a client
3.2. Overview
In this portion of the assignment you will be implementing a set of DTO classes that will be used to represent a AutoRental. All information expressed in the AutoRental will be derived from the Auto and Renter objects — except for the ID and the milestone properties.
Lecture/Assignment Module Ordering
It is helpful to have a data model in place before writing your services.
However, the lectures are structured with a content-less (String) domain up front — focusing on the Web API and services before tackling content.
If you are starting this portion of the assignment before we have covered the details of content, it is suggested that you simply create sparsely populated AutoRentalDTO class with at least an id field and the AutoRentalListDTO class to be able to complete the API interfaces.
Skip the details of this section until we have covered the Web content lecture.
|
AutoRental.id Avoids Compound Primary Key
The AutoRentalDTO id was added to keep from having to use a compound (autoId + renterId) primary key.
This makes it an easier 1:1 example with Auto and Renter to follow.
|
String Primary Keys
Strings were used for the primary key type.
This will make it much easier and more portable when we use database repositories in a later assignment.
|
The provided autorenters-support-api-dto
module has the Auto and Renter DTO classes.
-
AutoDTO - provides information specific to the auto
-
RenterDTO - provides information specific to the renter
-
StreetAddress - provides properties specific to a location for the Auto
-
MessageDTO - commonly used to provide error message information for request failures
-
<Type>ListDTO - used used to conveniently express typed collection of objects
MessageDTO is from ejava-dto-util Class Examples
A MessageDTO is supplied in the ejava-dto-util package and used in most of the class API examples.
You are free to create your own for use with the AutoRentals portion of the assignment.
|
3.3. Requirements
-
Create a DTO class to represent AutoRental. Use the attributes in the diagram above and descriptions below as candidate properties for each class.
-
The following attributes can be expressed both client and server-side
-
autoId
- required and an external reference toAuto
-
renterId
- required and an external reference toRenter
-
startDate
- required can be before or equal toendDate
-
endDate
- required and must be after or equal tostartDate
TimeSpan ClassI have provided aTimeSpan
utility class that can be used as an optional compound encapsulation ofstartDate
andendDate
when accessing properties of the AutoRental DTO. It can also be optionally leveraged for time span overlap comparisons.
-
-
The following attributes are only assigned server-side.
-
id
is a unique ID for a AutoRental -
makeModel
should be a concatenation of Auto.make and Auto.model such that an evaluation of the string will contain the original make and model string values -
renterName
should be the concatenation of Renter.firstName and Renter.lastName such that an evaluation of the string will contain the original first and lastName string values -
renterAge
should be a calculation of years, rounded down, between theRenter.dob
and the date the AutoRental starts.
-
-
streetAddress
should be a deep copy of the Auto.location
-
-
Create a
AutoRentalListDTO
class to provide a typed collection ofAutoRentalDTO
.I am recommending you name the collection within the class a generic contents
for later reuse reasons. -
Map each DTO class to:
-
Jackson JSON (the only required form)
-
mapping to Jackson XML is optional
-
-
Create a unit test to verify your new DTO type(s) can be marshalled/unmarshalled to/from the targeted serialization type.
-
API TODO: Annotate controller methods to consume and produce supported content type(s) when they are implemented.
-
API TODO: Update clients used in unit tests to explicitly only accept supported content type(s) when they are implemented.
3.4. Grading
Your solution will be evaluated on:
-
design a set of Data Transfer Objects (DTOs) to render information from and to the service
-
whether DTO class(es) represent the data requirements of the assignment
-
-
define a Java class content type mappings to customize marshalling/unmarshalling
-
whether unit test(s) successfully demonstrate the ability to marshall and unmarshal to/from a content format
-
-
API TODO: specify content types consumed and produced by a controller
-
whether controller methods are explicitly annotated with consumes and produces definitions for supported content type(s)
-
-
API TODO: specify content types accepted by a client
-
whether the clients in the unit integration tests have been configured to explicitly supply and accept supported content type(s).
-
3.5. Additional Details
-
This portion of the assignment alone primarily produces a set of information classes that make up the primary vocabulary of your API and service classes.
-
Use of
lombok
is highly encouraged here and can tremendously reduce the amount of code you write for these classes -
The Java
Period
class can easily calculate age in years between twoLocalDates
. ATimePeriod
class has been provided in the DTO package to aggregate startDate and endDate LocalDates together and to provide convenience methods related to those values. -
The
autorenters-support-api-client
module also provides aAutoDTOFactory
,RenterDTOFactory
, andStreetAddressDTOFactory
that makes it easy for tests and other demonstration code to quickly assembly example instances. You are encouraged to follow that pattern. -
The
autorenters-support-api-client
test cases for Auto and Renter demonstrate marshalling and unmarshalling DTO classes within a JUnit test. You should create a similar test of yourAutoRenterDTO
class to satisfy the testing requirement. Note that those tests leverage aJsonUtil
class that is part of the class utility examples and simplifies example use of the Jackson JSON parser. -
The
autorenters-support-api-client
and supplied starter unit tests make use of JUnit@ParameterizedTest
— which allows a single JUnit test method to be executed N times with variable parameters — pretty cool feature. Try it. -
Supporting multiple content types is harder than it initially looks — especially when trying to mix different libraries. WebClient does not currently support Jackson XML and will attempt to resort to using JAXB in the client. I provide an example of this later in the semester (Spring Data JPA End-to-End) and advise you to address the optional XML mapping last after all other requirements of the assignment are complete. If you do attempt to tackle both XML and WebClient together, know to use JacksonXML mappings for the server-side and JAXB mappings for the client-side.
4. Assignment 2c: Resources
4.1. Purpose
In this portion of the assignment, you will demonstrate your knowledge of designing a simple Web API. You will:
-
identify resources
-
define a URI for a resource
-
define the proper method for a call against a resource
-
identify appropriate response code family and value to use in certain circumstances
4.2. Overview
In this portion of the assignment you will be identifying a resource to implement the AutoRental API. Your results will be documented in a @RestController class. There is nothing to test here until the DTO and service classes are implemented.
The API will include three main concepts:
-
Autos (provided) - an individual auto that can be part of a auto rental
-
Auto information can be created, modified, listed, and deleted
-
Auto information can be modified or deleted at any time but changes do not impact previous auto rentals
-
-
Renters (provided) - identification for a person that may participate in a auto rental
-
Renter information can be created, modified, listed, and deleted
-
Renter information can be modified or deleted at any time but changes do not impact previous auto rentals
-
-
AutoRentals (your assignment) - a transaction for one Auto and one Renter for a unique period of time
-
AutoRental information can be created, modified, listed, and deleted
-
business rules will be applied for new and modified AutoRentals
-
4.3. Requirements
Capture the expression of the following requirements in a set of @RestController
class(es) to represent your resources, URIs, required methods, and status codes.
-
Identify your base resource(s) and sub-resource(s)
-
create URIs to represent each resource and sub-resource
Example Skeletal API Definitionspublic interface AutosAPI { String AUTOS_PATH="/api/autos"; String AUTO_PATH="/api/autos/{id}"; ...
-
create a separate
@RestController
class — at a minimum — for each base resourceExample Skeletal Controller@RestController public class AutosController {
-
-
Identify the
@RestController
methods required to represent the following actions for AutoRental. Assign them specific URIs and HTTP methods.-
create new AutoRental resource (a "contract")
-
Auto and Renter must exist
-
provided time period must be current or future dates
-
provided time period must not overlap with existing AutoRental for the same Auto for two different Renters (same Renter may have overlapping AutoRentals)
-
Renter must be at least 21 on startDate of rental
-
-
update an existing AutoRental resource
-
modified time period must be current or future dates
-
modified time period must not overlap with existing AutoRental for the same Auto for two different Renters
-
-
get a specific AutoRental resource
-
list AutoRental resources with paging
-
accept optional autoId, renterId, and time period query parameters
-
accept optional pageNumber, pageSize, and optional query parameters
-
return
AutoRentalListDTO
containing contents ofList<AutoRentalDTO>
-
-
delete a specific resource
-
delete all instances of the resource
Example Skeletal Controller Method@RequestMapping(path=AutosAPI.AUTO_PATH, method = RequestMethod.POST, consumes = {...}, produces = {...}) public ResponseEntity<AutoDTO> createAuto(@RequestBody AutoDTO newAuto) { throw new RuntimeException("not implemented"); //or return ResponseEntity.status(HttpStatus.CREATED).body(...); }
-
-
CLIENT TODO: Identify the response status codes to be returned for each of the actions
-
account for success and failure conditions
-
authorization does not need to be taken into account at this time
-
4.4. Grading
Your solution will be evaluated on:
-
identify resources
-
whether your identified resource(s) represent thing(s)
-
-
define a URI for a resource
-
whether the URI(s) center on the resource versus actions performed on the resource
-
-
define the proper method for a call against a resource
-
whether proper HTTP methods have been chosen to represent appropriate actions
-
-
CLIENT TODO: identify appropriate response code family and value to use in certain circumstances
-
whether proper response codes been identified for each action
-
4.5. Additional Details
-
This portion of the assignment alone should produce a
@RestController
class with annotated methods that statically define your API interface (possibly missing content details). There is nothing to run or test in this portion alone. -
A simple and useful way of expressing your URIs can be through defining a set of public static attributes expressing the collection and individual instance of the resource type.
Example Template Resource DeclarationString (RESOURCE)S_PATH="(path)"; String (RESOURCE)_PATH="(path)/{identifier(s)}";
-
If you start with this portion, you may find it helpful to
-
create sparsely populated DTO classes —
AutoRentalDTO
with just anid
andAutoRentalListDTO
— to represent the payloads that are accepted and returned from the methods -
have the controller simply throw a RuntimeException indicating that the method is not yet implemented. That would be a good excuse to also establish an exception advice to handle thrown exceptions.
-
-
The details of the AutoRental will be performed server-side — based upon IDs and properties provided by the client and the Auto and Renter values found server-side. The client never provides more than an ID for an Auto or Renter and if it does — the server-side must ignore and rely on the server-side source for details.
-
There is nothing to code up relative to response codes at this point. However:
-
Finding zero resources to list is not a failure. It is a success with no resources in the collection.
-
Not finding a specific resource is a failure and the status code returned should reflect that.
-
Instances of Action Verbs can be Resource Nouns
If an action does not map cleanly to a resource+HTTP method, consider thinking of the action (e.g., cancel) as one instance of an action (e.g., cancellation) that is a sub-resource of the subject (e.g., subjects/{subjectId}/cancellations). How might you think of the action if it took days to complete? (e.g. a sub-resource with POST/create(), GET/isComplete(), PUT/changePriority(), and DELETE/terminate()) |
5. Assignment 2d: Client/API Interactions
5.1. Purpose
In this portion of the assignment, you will demonstrate your knowledge of designing and implementing the interaction between a Web client and API. You will:
-
implement a service method with Spring MVC synchronous annotated controller
-
implement a client using
RestTemplate
orRestClient
-
pass parameters between client and service over HTTP
-
return HTTP response details from service
-
access HTTP response details in client
5.2. Overview
In this portion of the assignment you will invoke your resource’s Web API from a client running within a JUnit test case.
There will be at least two primary tests in this portion of the assignment: handling success and handling failure. The failure will be either real or simulated through a temporary resource stub implementation.
5.3. Requirements
-
Implement stub behavior in the controller class as necessary to complete the example end-to-end calls.
Example Stub ResponseAutoDTO newRental = AutoDTO.builder().id("1").build() URI location = ServletUriComponentsBuilder.fromCurrentRequestUri() .replacePath(AUTORENTAL_PATH) .build("1"); return ResponseEntity.created(location).body(newRental);
-
Implement a unit integration test to demonstrate a success path
-
use either a
RestTemplate
orRestClient
API client class for this test. You may also leverage Spring HTTP Interface. -
make at least one call that passes parameter(s) to the service and the results of the call depend on that passed parameter value
-
access the return status and payload in the JUnit test/client
-
evaluate the result based on the provided parameter(s) and expected success status
Example Response Evaluationthen(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); then(response.getHeaders().getLocation()).isNotEmpty(); then(autoResult.getId()).isNotBlank(); then(autoResult).isEqualTo(autoRequestDTO.withId(autoResult.getId()));
-
Examples use RestTemplate
The Auto and Renter examples only use the RestTemplate and Spring HTTP Interface approaches.
|
One Success, One Failure, and Move On
Don’t put too much work into more than a single success and failure path test before completing more of the end-to-end.
Your status and details will likely change.
|
5.4. Grading
Your solution will be evaluated on:
-
implement a service method with Spring MVC synchronous annotated controller
-
whether your solution implements the intended round-trip behavior for an HTTP API call to a service component
-
-
implement a client using
RestTemplate
orRestClient
-
whether you are able to perform an API call using either the
RestTemplate
,RestClient
, or Spring HTTP Interface APIs
-
-
pass parameters between client and service over HTTP
-
whether you are able to successfully pass necessary parameters between the client and service
-
-
return HTTP response details from service
-
whether you are able to return service response details to the API client
-
-
access HTTP response details in client
-
whether you are able to access HTTP status and response payload
-
5.5. Additional Details
-
The required end-to-end tests in the last section requires many specific success and failure test scenarios. View this portion of the assignment as just an early draft work of those scenarios. If you have completed the end-to-end tests, you have completed this portion of the assignment.
-
Your DTO class(es) have been placed in your Client module in a separate section of this assignment. You may want to add an optional API client class to that Client module — to encapsulate the details of the HTTP calls. The
autorenters-support-client
module contains example client API classes for Autos and Renters usingRestTemplate
and Spring HTTP Interface. -
Avoid placing extensive business logic into the stub portion of the assignment. The controller method details are part of a separate section of this assignment.
-
This portion of the assignment alone should produce a simple, but significant demonstration of client/API communications (success and failure) using HTTP and service as the model for implementing additional resource actions.
-
Inject the dependencies for the test from the Spring context. Anything that depends on the server’s port number must be delayed (
@Lazy
)@Bean @Lazy (2) public ServerConfig serverConfig(@LocalServerPort int port) { (1) return new ServerConfig().withPort(port).build(); } @Bean @Lazy (3) public AutosAPI autosAPI(RestTemplate restTemplate, ServerConfig serverConfig) { return new AutosAPIClient(restTemplate, serverConfig, MediaType.APPLICATION_JSON); } @SpringBootTest(...webEnvironment=... public class AutoRentalsAPINTest { @Autowired private AutosAPI autoAPI;
1 server’s port# is not known until runtime 2 cannot eagerly create @Bean
until server port number available3 cannot eagerly create dependents of port number
6. Assignment 2e: Service/Controller Interface
6.1. Purpose
In this portion of the assignment, you will demonstrate your knowledge of separating the Web API facade details from the service implementation details and integrating the two. You will:
-
implement a service class to encapsulate business logic
-
turn @RestController class into a facade and delegate business logic details to an injected service class
-
implement an error reporting strategy
6.2. Overview
In this portion of the assignment you will be implementing the core of the AutoRental components and integrating them as seamlessly as possible.
-
the controller will delegate commands to a service class to implement the business logic.
-
the service will use internal logic and external services to implement the details of the business logic.
-
the repository will provide storage for the service.
Your Assignment is Primarily AutoRental and Integration
You have been provided complete implementation of the Auto and Renter services.
You only have to implement the AutoRental components and integration that with Auto and Renter services .
|
A significant detail in this portion of the assignment is to design a way to convey success and failure when carrying out an API command. The controller should act only as a web facade. The service(s) will implement the details of the services and report the results.
Under the hood of the AutoRentalService
is a repository and external clients.
-
You will create a
AutoRentalService
interface that usesAutoRentalDTO
as its primary data type. This interface can be made reusable through the full semester of assignments.
This assignment will only work with DTO types (no entities/BOs) and a simulated/stub Repository.
-
You will create a repository interface and implementation that mimic the behavior of a CRUD and Pageable Repository of a future assignment.
-
You will inject and implement calls to the Auto and Renter services.
6.3. Requirements
-
Implement a AutoRentalDTORepository interface and implementation component to simulate necessary behavior (e.g., save, findById, find) for the base AutoRentalDTO resource type. Don’t go overboard here. We just need some place to generate IDs and hold the data in memory.
-
implement a Java interface (e.g.,
AutoRentalDTORepository
).Try to make this interface conceptually consistent with the Spring Data ListCrudRepository and ListPagingAndSortingRepository (including the use of Pageable and Page) to avoid changes later on. This is just a tip and not a requirement — implement what you need for now. Start with just save()
. -
implement a component class stub (e.g.,
AutoRentalDTORepositoryStub
) using simple, in-memory storage (e.g.,HashMap
orConcurrentHashMap
) and an ID generation mechanism (e.g.,int
orAtomicInteger
)
You are free to make use of the POJORepositoryMapImpl<T>
class in theautorentals_support_api
module as your implementation for the repository. It comes with aPOJORepository<T>
interface and the Renter repository and service provide an example of its use. Report any bugs you find. -
-
Implement a AutoRental service to implement actions and enforce business logic on the base resources
-
implement a Java interface This will accept and return AutoRentalDTO types.
-
implement a component class for the service.
-
inject the dependencies required to implement the business logic
-
(provided)
AutosService
- to verify existence of and obtain details of autos -
(provided)
RentersService
- to verify existence of and obtain details of renters -
(your assignment)
AutoRentalDTORepository
- to store details that are important to auto rentalsYou are injecting the service implementations (not the HTTP API) for the Auto and Renter services into your AutoRental service. That means they will be part of your application and you will have a Java ⇒ Java interface with them.
-
-
implement the business logic for the service
-
a AutoRental can only be created for an existing Auto and Renter. It will be populated using the values of that Auto and Renter on the server-side.
-
autoId
(mandatory input) — used to locate the details of the Auto on the server-side -
renterId
(mandatory input) — used to locate the details of the Renter on the server-side -
startDate
(mandatory input) — used to indicate when the Rental will begin. This must be in the future and before or equal toendDate
. -
endDate
(mandatory input) — used to indicate when the Rental will end. This must be after or equal tobeginDate
.
-
-
AutoRental must populate the following fields from the Auto and Renter obtained server-side using the autoId and renterId.
-
from the server-side Auto
-
makeModel
— derived from the Auto’smake
andmodel
details obtained server-side -
amount
— calculated from Auto.dailyRate * days in time span
-
-
from the server-side
Renter
-
renterName
— derived from the Renter’sfirstName
andlastName
details on the server-side -
renterAge
— calculated form thestartDate
andRenter
dob
details on the server-side. A Renter must be at least 21 onstartDate
to be valid. The rejection shall include the text "too young".
-
-
-
beginDate/endDate
time span cannot overlap with another AutoRental for the same Auto for a different Renter. The rejection shall include the text "conflict". -
a successful request to create a AutoRental will be returned with
-
the above checks made, id assigned, and a 201/CREATED http status returned
-
properties (
makeModel
,renterName
renterAge
,amount
) filled in
-
-
getAutoRental returns current state of the requested AutoRental
-
implement a paged
findAutoRentals
that returns all matches. Use the Spring DataPageable
andPage
(andPageImpl
) classes to express pageNumber, pageSize, and page results (i.e.,Page findAutoRentals(Pageable)
). You do not need to implement sort. -
augment the
findAutoRentals
to optionally include a search for matching autoId, renterId, time span (startDate
andendDate
), or any combination.Implement Search Details within Repository classDelegate the gory details of searching through the data — to the repository class.
-
-
-
Design a means for service calls to
-
indicate success
-
indicate failure to include internal or client error reason. Client error reasons must include separate issues "not found" and "bad request" at a minimum.
-
-
Integrate services into controller components
-
complete and report successful results to API client
-
report errors to API client, to include the status code and a textual message that is specific to the error that just occurred
-
-
Implement a unit integration test to demonstrate at least one success and error path
-
access the return status and payload in the client
-
evaluate the result based on the provided parameter(s) and expected success/failure status
-
6.4. Grading
Your solution will be evaluated on:
-
implement a service class to encapsulate business logic
-
whether your service class performs the actions of the service and acts as the primary enforcer of stated business rules
-
-
turn @RestController class into a facade and delegate business logic details to an injected service class
-
whether your API tier of classes act as a thin adapter facade between the HTTP protocol and service component interactions
-
-
implement an error reporting strategy
-
whether your design has identified how errors are reported by the service tier and below
-
whether your API tier is able to translate errors into meaningful error responses to the client
-
6.5. Additional Details
-
This portion of the assignment alone primarily provides an implementation pattern for how services will report successful and unsuccessful requests and how the API will turn that into a meaningful HTTP response that the client can access.
-
The
autorenters-support-api-svc
module contains a set of example DTO Repository Stubs.-
The
Autos
package shows an example of a fully exploded implementation. Take this approach if you wish to write all the code yourself. -
The
Renters
package shows an example of how to use the templatedPOJORepository<T>
interface andPOJORepositoryMapImpl<T>
implementation. Take this approach if you want to delegate to an existing implementation and only provide the custom query methods.
POJORepositoryMapImpl<T>
provides a protectedfindAll(Predicate<T> predicate, Pageable pageable)
that returns aPage<T>
. All you have to provide are the predicates for the custom query methods. -
-
You are required to use the
Pageable
andPage
classes (from theorg.springframework.data.domain
Java package) for paging methods in your finder methods — to be forward compatible with later assignments that make use of Spring Data. You can find example use ofPageable
andPage
(andPageImpl
) in Auto and Renter examples. -
It is highly recommend that exceptions be used between the service and controller layers to identify error scenarios and specific exceptions be used to help identify which kind of error is occurring in order to report accurate status to the client. Leave non-exception paths for successful results. The Autos and Renters example leverage the exceptions defined in the
ejava-dto-util
module. You are free to define your own. -
It is highly recommended that
ExceptionHandlers
andRestExceptionAdvice
be used to handle exceptions thrown and report status. The Autos and Renters example leverage theExceptionHandlers
from theejava-web-util
module. You are free to define your own.
7. Assignment 2f: Required Test Scenarios
There are a set of minimum scenarios that are required of a complete project that must be specifically demonstrated in the submission.
-
Creation of AutoRental
-
success (201/
CREATED
) -
failed creation because Auto unknown (422/
UNPROCESSABLE_ENTITY
) -
failed creation because Auto unavailable for time span (422/
UNPROCESSABLE_ENTITY
) -
failed creation because Renter unknown (422/
UNPROCESSABLE_ENTITY
) -
failed creation because Renter too young (422/
UNPROCESSABLE_ENTITY
)
-
-
Update of AutoRental
-
success (200/
OK
) -
failed because AutoRental does not exist (404/
NOT_FOUND
) -
failed because AutoRental exists but change is invalid (422/
UNPROCESSABLE_ENTITY
)
-
7.1. Scenario: Creation of AutoRental
In this scenario, an AutoRental is attempted to be created.
7.1.1. Primary Path: Success
In this primary path, the Auto and Renter exist, all business rules are satisfied, and the API client is able to successfully create an AutoRental. The desired status in the response is a 201/CREATED. A follow-on query for AutoRentals will report the new entry.
7.1.2. Alternate Path: Auto unknown
In this alternate path, the Auto does not exist and the API client is unable to create a AutoRental. The desired response status is a 422/UNPROCESSABLE_ENTITY. The AutoRentals resource understood the request (i.e., not a 400/BAD_REQUEST or 404/NOT_FOUND), but request contained information that could not be processed.
getAuto() will return a 404/NOT_FOUND — which is not the same status requested here. AutoRentals will need to account for that difference. |
7.1.3. Alternate Path: Auto Unavailable
In this alternate path, the Auto exists but is unavailable for the requested time span. The desired response status is a 422/UNPROCESSABLE_ENTITY. The AutoRentals resource understood the request, but request contained information that could not be processed.
7.1.4. Alternate Path: Renter Unknown
In this alternate path, the Renter does not exist and the API client is unable to create a AutoRental for the Renter. The desired response status is a 422/UNPROCESSABLE_ENTITY.
getRenter() will return a 404/NOT_FOUND — which is not the same status requested here. AutoRentals will need to account for that difference. |
7.1.5. Alternate Path: Renter Too Young
In this alternate path, the Renter exists but is too young to complete a AutoRental. The desired response status is a 422/UNPROCESSABLE_ENTITY.
7.2. Scenario: Update of AutoRental
In this scenario, a AutoRental is attempted to be updated.
7.2.1. Primary Path: Success
In this primary path, the API client is able to successfully update the time span for an AutoRental. This update should be performed all on the server-side. The client primarily expresses an updated proposal and the business rules pass. A follow-on query for AutoRentals will report the updated entry.
7.2.2. Alternate Path: AutoRental does not exist
In this alternate path, the requested AutoRental does not exist.
The expected response status code should be 404/NOT_FOUND
to express that the target resource could not be found.
7.2.3. Alternate Path: Invalid Change
In this alternate path, the requested AutoRental exists but the existing Auto is not available for the new time span.
The expected response status code should be 422/UNPROCESSABLE_ENTITY
.
The scenario is showing that only the time span is being changed and the existing Auto and Renter should be used. The scenario is also showing that the existing Auto and Renter are being verified to still exist. |
7.3. Requirements
-
Implement the above scenarios within one or more integration unit tests.
-
Name the tests such that they are picked up and executed by the Surefire test phase of the maven build.
-
Turn in a cleaned source tree of the project under a single root parent project. The Auto and Renter modules do not need to be included.
-
The source tree should be ready to build in an external area that has access to the ejava-nexus-snaphots repository.
7.4. Grading
-
create an integration test that verifies a successful scenario
-
whether you implemented a set of integration unit tests that verify the primary paths for AutoRentals
-
-
create an integration test that verifies a failure scenario
-
whether you implemented a set of integration unit tests that verify the failure paths for AutoRentals.
-
7.5. Additional Details
-
Place behavior in the proper place
-
The unit integration test is responsible for populating the Autos and Renters. It will supply AutoDTOs and RenterDTOs populated on the client-side — to the Autos and Renters APIs/services.
-
The unit integration test will pass sparsely populated AutoRentalDTOs to the server-side with autoId, renterId, etc. values express inputs for creating a listing or making a purchase. All details to populate the returned
AutoRentalDTOs
(i.e., Auto and Renter info) will come from the server-side. There should never be a need for the client to self-create/fully-populate a AutoRentalDTO.
-