This sample app shows how to use Fauna in a production application.
The app uses Java 17 with Gradle 8.9 and the Fauna v10 JVM driver to create HTTP API endpoints for an e-commerce store. You can use the app's API endpoints to manage products, customers, and orders for the store.
The app uses Fauna schemas and queries to:
-
Read and write data with strong consistency.
-
Define and handle relationships between resources, such as linking orders to products and customers.
-
Validate data changes against business logic.
The app's source code includes comments that highlight Fauna best practices.
The sample app uses the following Fauna features:
-
Document type enforcement: Collection schemas enforce a structure for the app's documents. Fauna rejects document writes that don't conform to the schema, ensuring data consistency. Zero-downtime migrations let you safely change the schemas at any time.
-
Relationships: Normalized references link documents across collections. The app's queries use projection to dynamically retrieve linked documents, even when deeply nested. No complex joins, aggregations, or duplication needed.
-
Computed fields: Computed fields dynamically calculate their values at query time. For example, each customer's
orders
field uses a query to fetch a set of filtered orders. Similarly, each order'stotal
is calculated at query time based on linked product prices and quantity. -
Constraints: The app uses constraints to ensure field values are valid. For example, the app uses unique constraints to ensure each customer has a unique email address and each product has a unique name. Similarly, check constraints ensure each customer has only one cart at a time and that product prices are not negative.
-
User-defined functions (UDFs): The app uses UDFs to store business logic as reusable queries. For example, the app uses a
checkout()
UDF to process order updates.checkout()
calls another UDF,validateOrderStatusTransition()
, to validatestatus
transitions for orders.
To run the app, you'll need:
-
A Fauna account. You can sign up for a free account at https://dashboard.fauna.com/register.
-
Your preferred flavor of Java 17
-
Fauna CLI v3.0.0 or later.
To install the CLI, run:
npm install -g fauna-shell@latest
You should also be familiar with basic Fauna CLI commands and usage. For an overview, see the Fauna CLI docs.
-
Clone the repo and navigate to the
java-sample-app
directory:git clone git@github.com:fauna/java-sample-app.git cd java-sample-app
-
Log in to Fauna using the Fauna CLI:
fauna cloud-login
When prompted, enter:
- Endpoint name:
cloud
(Press Enter) - Email address: The email address for your Fauna account.
- Password: The password for your Fauna account.
- Which endpoint would you like to set as default? The
cloud-*
endpoint for your preferred region group. For example, to use the US region group, usecloud-us
.
The command requires an email and password login. If you log in to the Fauna using GitHub or Netlify, you can enable email and password login using the Forgot Password workflow.
- Endpoint name:
-
Use the Fauna CLI to create the
ECommerceJava
database:fauna create-database ECommerceJava
-
Create a
.fauna-project
config file for the project:fauna project init
When prompted, enter:
schema
as the schema directory.dev
as the environment name.- The default endpoint.
ECommerce
as the database.
-
Push the
.fsl
files in theschema
directory to theECommerceJava
database:fauna schema push
When prompted, accept and stage the schema.
-
Check the status of the staged schema:
fauna schema status
-
When the status is
ready
, commit the staged schema to the database:fauna schema commit
The commit applies the staged schema to the database. The commit creates the collections and user-defined functions (UDFs) defined in the
.fsl
files of theschema
directory. -
Create a key with the
server
role for theECommerceJava
database:fauna create-key --environment='' ECommerceJava server
Copy the returned
secret
. The app can use the key's secret to authenticate requests to the database.
The app includes a setup script that adds sample documents to the
ECommerceJava
database. From the root directory, run:
FAUNA_SECRET=<secret> ./setup.sh
You can view documents created by the script in the Fauna Dashboard.
The app runs an HTTP API server. From the root directory, run:
FAUNA_SECRET=<secret> ./gradlew bootRun
Once started, the local server is available at http://localhost:8080.
The app's HTTP API endpoints are defined in *Controller
files in the
java.sample.controllers.*
modules.
An OpenAPI spec and Swagger UI docs for the endpoints are available at:
- OpenAPI spec: http://localhost:8080/v3/api-docs
- Swagger UI: http://localhost:8080/swagger-ui.html
You can use the endpoints to make API requests that read and write data from
the ECommerceJava
database.
For example, with the local server running in a separate terminal tab, run the
following curl request to the POST /products
endpoint. The request creates a
Product
collection document in the ECommerceJava
database.
curl -v \
http://localhost:8080/products \
-H "Content-Type: application/json" \
-d '{
"name": "The Old Man and the Sea",
"price": 899,
"description": "A book by Ernest Hemingway",
"stockQuantity": 10,
"category": "books"
}' | jq .
You can further expand the app by adding fields and endpoints.
As an example, the following steps adds a computed totalPurchaseAmt
field to
Customer documents and related API responses:
-
If you haven't already, add the sample data:
FAUNA_SECRET=<secret> ./setup.sh
If the app server is running, stop the server by pressing Ctrl+C.
-
In
schema/collections.fsl
, add the followingtotalPurchaseAmt
computed field definition to theCustomer
collection:collection Customer { ... // Use a computed field to get the set of Orders for a customer. compute orders: Set<Order> = (customer => Order.byCustomer(customer)) + // Use a computed field to calculate the customer's cumulative purchase total. + // The field sums purchase `total` values from the customer's linked Order documents. + compute totalPurchaseAmt: Number = (customer => customer.orders.fold(0, (sum, order) => { + let order: Any = order + sum + order.total + })) ... } ...
Save
schema/collections.fsl
. -
Push the updated
.fsl
files in theschema
directory to theECommerceJava
database to stage the changes:fauna schema push
When prompted, accept and stage the schema.
-
Check the status of the staged schema:
fauna schema status
-
When the status is
ready
, commit the staged schema changes to the database:fauna schema commit
-
In
CustomersController.java
, add thetotalPurchaseAmt
field to theresponse
FQL template:// Project Customer document fields for consistent responses. private final Query response = fql(""" customer { id, name, email, + address, + totalPurchaseAmt } """); `;
Save
CustomersController.java
.Customer-related endpoints use this template to project Customer document fields in responses.
-
In
Customer.java
, add thetotalPurchaseAmt
field and a related getter to theCustomer
class:private String email; private Address address; + private int totalPurchaseAmt; + + public int getTotalPurchaseAmt() { + return totalPurchaseAmt; + } public String getId() { return id; }
Save
Customer.java
.Customer-related endpoints return responses that conform to the
Customer
class. -
Start the app server:
FAUNA_SECRET=<secret> ./gradlew bootRun
-
With the local server running in a separate terminal tab, run the following curl request to the
POST /customers
endpoint:curl -v http://localhost:8080/customers/999 | jq .
The response includes the computed
totalPurchaseAmt
field:{ "id": "999", "name": "Valued Customer", "email": "fake@fauna.com", "address": { "street": "Herengracht", "city": "Amsterdam", "state": "North Holland", "postalCode": "1015BT", "country": "Netherlands" }, "totalPurchaseAmt": 36000 }