Implementation of the sample from REST in Practice based on Spring projects
Implementation of the sample from REST in Practice based on Spring projects
This project is a sample implementation of the Restbucks application described in the book REST in Practice by Jim Webber, Savas Parastatidis and Ian Robinson. It's a showcase for bringing different Spring eco-system technologies together to implement a REST web service. The application uses HAL as the primary representation format. The server implementation is accompanied by a hypermedia-aware Android client that adapts to changes on the server dynamically.
From the command line do:
git clone https://github.com/odrotbohm/spring-restbucks.git
cd spring-restbucks/server
mvn clean package
java -jar target/*.jarTo send requests to the server application, you have several choices:
1. Use the embedded HAL Explorer.
The application ships with HAL Explorer embedded, so simply browsing to http://localhost:8080/explorer/index.html#uri=/ will allow you to explore the web service.
To get or create an order via HAL Explorer, you can start by either getting existing orders or placing a new order:
restbucks:orders relation under Links. In the pop-up, click Go!, then expand any of the orders listed under Embedded Resources and click on self.Place an order under HAL-FORMS Template Elements.Once you have an order displayed in HAL Explorer, you can submit payment:
Go to checkout under HAL-FORMS Template Elements. This template appears for all orders with status Payment expected.Credit card nuumber field and click Go!1234123412341234 and the payment will succeed. Ollie has got you covered :)Note, that the curie links in the representations are currently not backed by any documents served but they will be in the future. Imagine simple HTML pages being served documenting the individual relation types.
2. Use the Android client.
Refer to the section The Android client below for more information.
3. Use the provided bash scripts.
Two bash scripts are provided to generate traffic. Both require curl and jq.
Single-run script: scripts/generate-traffic.sh
By default it places a single order (first available drink, default location), pays with the built-in demo card (1234123412341234), and polls until a receipt link appears. You can run multiple or varied scenarios, force errors, add delays, and more.
Usage examples:
./scripts/generate-traffic.sh./scripts/generate-traffic.sh --scenarios scripts/order-scenarios.json./scripts/generate-traffic.sh --scenarios scripts/order-scenarios.json --scenario java_chip_takeaway --force-error INVALID_CARD./scripts/generate-traffic.sh --scenarios scripts/order-scenarios.json --cycle./scripts/generate-traffic.sh --scenarios scripts/order-scenarios.json --random-scenario./scripts/generate-traffic.sh --scenarios scripts/order-scenarios.json --random-scenario --cycle./scripts/generate-traffic.sh --scenarios scripts/order-scenarios.json --cycle --no-delayOptions for generate-traffic.sh:
--scenarios or --scenarios= — JSON file of scenarios (e.g. scripts/order-scenarios.json). Without --scenario, runs all scenarios in order; with --scenario , runs only that scenario.--scenario or --scenario= — Run only the named scenario.--cycle — With --scenarios: repeat indefinitely (Ctrl+C to stop). Without --scenario cycles through all; with --scenario repeats that scenario.--random-scenario — With --scenarios and no --scenario: run one scenario chosen at random. With --cycle, pick a new random scenario each iteration.--delay-max — Random delay 0..MS milliseconds between scenario runs (default 3000). Use --no-delay for no delay.--force-error [INVALID_CARD|DOUBLE_PAY] — INVALID_CARD: invalid card, expect failure. DOUBLE_PAY: pay twice, second payment fails. Omitted value defaults to INVALID_CARD.--base-url — Target base URL (default http://localhost:8080).--verbose / -v — DEBUG-level payload dumps.Parallel users: scripts/run-parallel-traffic.sh
Runs multiple “users” in parallel, each executing generate-traffic.sh with --scenarios scripts/order-scenarios.json --random-scenario --cycle. Output is prefixed with [n]> for user number n. A single Ctrl+C stops all users.
Usage (run from the server directory):
./scripts/run-parallel-traffic.sh./scripts/run-parallel-traffic.sh 10./scripts/run-parallel-traffic.sh 3 --verboseFor the usage inside an IDE do the following:
Make sure you have an Eclipse with m2e installed (preferably STS).
Install Lombok.
java -jar …).Import the checked out code through File > Import > Existing Maven Project…
server/pom.xml and select Add as Maven Project.Run panel (activated by right-clicking on server/src/test/java/org/springsource/restbucks and selecting Run Tests in 'restbucks'), you will need to edit Maven plugin configurations. Open the Maven tool window and find the list of plugins included in the project. Expand byte-buddy, right click on transform-extended, and select Execute After Build and Execute After Rebuild.The project uses:
The implementation consists of mainly two parts, the order and the payment part. The Orders are exposed as REST resources using Spring Data RESTs capability to automatically expose Spring Data JPA repositories contained in the application. The Payment process and the REST application protocol described in the book are implemented manually using a Spring MVC controller (PaymentController).
Here's what the individual projects used contribute to the sample in from a high-level point of view:
The Spring Data repository mechanism is used to reduce the effort to implement persistence for the domain objects to the declaration of an interface per aggregate root. See OrderRepository and PaymentRepository for example. Beyond that, using the repository abstract enables the Spring Data REST module to do its work.
We're using Spring Data REST to expose the OrderRepository as REST resource without additional effort.
Spring HATEOAS provides a generic Resource abstraction that we leverage to create hypermedia-driven representations. Spring Data REST also leverages this abstraction so that we can deploy ResourceProcessor implementations (e.g. PaymentorderResourceProcessor) to enrich the representations for Order instance with links to the PaymentController. Read more on that below in the Hypermedia section.
The final important piece is the EntityLinks abstraction that allows to create Link instance in a type-safe manner avoiding the repetition of URI templates and parts all over the place. See PaymentLinks for example usage.
The Spring Plugin library provides means to collect Spring beans by type and exposing them for selection based on a selection criterion. It basically forms the foundation for the EntityLinks mechanism provided in Spring HATEOAS and our custom extension RestResourceEntityLinks.
The spring-session branch contains additional configuration to secure the service using Spring Security, HTTP Basic authentication and Spring Session's HTTP header based session strategy to allow clients to obtain a security token via the X-Auth-Token header and using that for subsequent requests.
If you check out the branch and run the sample you should be able to follow this interaction (I am using HTTPie here)
$ http :8080
HTTP/1.1 401 Unauthorized
…
WWW-Authenticate: Basic realm="Spring RESTBucks"You can now authenticate using the default credentials (the password password is configured in application.properties).
$ http :8080 --auth=user:password
HTTP/1.1 200 OK
Content-Type: application/hal+json;charset=UTF-8
–
X-Auth-Token: ef005d62-b69b-4675-b920-d340a238e857Now you can use the presented auth token in further requests:
$ http :8080 X-Auth-Token:ef005d62-b69b-4675-b920-d340a238e857
HTTP/1.1 200 OK
Content-Type: application/hal+json;charset=UTF-8
–Spring Modulith supports modular architecture in monoliths. It treats each root-level package as a separate module with top-level public members exposed as API and all other code protected as module-internal (unless explicitly specified otherwise). Through tests, it verifies compliance to modular architecture rules and also generates documentation for architecturally relevant components of the system. See DocumentationTest and also target/spring-modulith-docs/, once the test has been executed.
Additionally, we are using Spring Modulith to isolate a single module for integration testing in OrdersIntegrationTest. We are also using Spring Modulith, together with Spring Framework's in-memory messaging capabilities, to handle event-driven interactions between modules with additional support for transaction management. See the use of ApplicationModuleListener in Engine.
Finally, Spring Modulith is being used to extract distributed tracing from module interactions. To enable this functionality, see the Observability section below.
The restdocs branch contains the test for the order payment process augmented with setup to generate Asciidoctor snippets documenting the executed requests and expectations on the responses.
These snippets are included from the general Asciidoctor documents in src/main/asciidoc, turned into HTML and packaged into the application itself during the build (run mvn clean package).
The docs are then pointed to by a CURIE link in the HAL response (see Restbucks.curieProvider()) so that they
No open issues yet, or sync has not completed.