This sample app shows how to use Fauna in a production application.
The app uses .NET and the Fauna v10 .NET 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.
-
.NET 8.0 or later.
-
Fauna CLI v4 beta or later.
- Node.js v20.x or later.
To install the CLI, run:
npm install -g fauna-shell@">=4.0.0-beta"
-
Clone the repo and navigate to the
dotnet-sample-app
directory:git clone [email protected]:fauna/dotnet-sample-app.git cd dotnet-sample-app
-
If you haven't already, log in to Fauna using the Fauna CLI:
fauna login
-
Use the Fauna CLI to create the
EcommerceDotnet
database:# Replace 'us' with your preferred Region Group: # 'us' (United States), 'eu' (Europe), or `global` (available to Pro accounts and above). fauna database create \ --name EcommerceDotnet \ --database us
-
Push the
.fsl
files in theschema
directory to theEcommerceDotnet
database:# Replace 'us' with your Region Group identifier. fauna schema push \ --database us/EcommerceDotnet
When prompted, accept and stage the schema.
-
Check the status of the staged schema:
fauna schema status \ --database us/EcommerceDotnet
-
When the status is
ready
, commit the staged schema to the database:fauna schema commit \ --database us/EcommerceDotnet
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
admin
role for theEcommerceDotnet
database:fauna query "Key.create({ role: 'admin' })" \ --database us/EcommerceDotnet
Copy the returned
secret
. The app can use the key's secret to authenticate requests to the database. -
Make a copy of the
.env.example
file and name the copy.env
. For example:cp .env.example .env
-
In
.env
, set theFAUNA_SECRET
environment variable to the secret you copied earlier:... FAUNA_SECRET=fn... ...
The app runs an HTTP API server. From the DotNetSampleApp
directory, run:
export $(grep -v '^#' .env | xargs) && \
FAUNA_SECRET=$FAUNA_SECRET dotnet run
Once started, the local server is available at http://localhost:5049.
You can also run the app in a Docker container. From the root directory, run:
docker build -t dotnet-sample-app .
export $(grep -v '^#' .env | xargs) && \
docker run -p 5049:8080 \
-e ASPNETCORE_ENVIRONMENT=Development \
-e FAUNA_SECRET=$FAUNA_SECRET \
dotnet-sample-app
Once started, the local server is available at http://localhost:5049.
The app includes seed data that's populated when you make a successful request to any API endpoint.
The app's HTTP API endpoints are defined in the DotNetSampleApp/Controllers
directory.
An OpenAPI spec and Swagger UI docs for the endpoints are available at:
- OpenAPI spec: http://localhost:5049/swagger/v1/swagger.json
- Swagger UI: http://localhost:5049/swagger/index.html
You can use the endpoints to make API requests that read and write data from
the EcommerceDotnet
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 EcommerceDotnet
database.
curl -v \
http://localhost:5049/products \
-H "Content-Type: application/json" \
-d '{
"name": "The Old Man and the Sea",
"price": 899,
"description": "A book by Ernest Hemingway",
"stock": 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 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
. -
In
DotNetSampleApp/Controllers/QuerySnippets.cs
, add thetotalPurchaseAmt
field to theCustomerResponse
method's projection:... customer { id, name, email, + address, + totalPurchaseAmt } ...
-
Push the updated schema to the
EcommerceDotnet
database:# Authenticated using the FAUNA_SECRET env var. 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
DotNetSampleApp/Models/Customer.cs
, add thetotalPurchaseAmt
field to theCustomer
class:public class Customer { /// <summary> /// Document ID /// </summary> [Id] public string? Id { get; init; } ... /// <summary> /// Address /// </summary> [Field] public required Address Address { get; init; } + /// <summary> + /// Total Purchase Amount + /// </summary> + [Field] + public required int TotalPurchaseAmt { get; init; } }
Save
DotNetSampleApp/Models/Customer.cs
.Customer-related endpoints use this template to project Customer document fields in responses.
-
Start the app server:
export $(grep -v '^#' .env | xargs) && \ FAUNA_SECRET=$FAUNA_SECRET dotnet run
If using Docker, run:
docker build -t dotnet-sample-app . export $(grep -v '^#' .env | xargs) && \ docker run -p 5049:8080 \ -e ASPNETCORE_ENVIRONMENT=Development \ -e FAUNA_SECRET=$FAUNA_SECRET \ dotnet-sample-app
-
With the local server running in a separate terminal tab, run the following curl request to the
POST /customers
endpoint:curl -v http://localhost:5049/customers/999 | jq .
The response includes the computed
totalPurchaseAmt
field:{ "id": "999", "name": "Valued Customer", "email": "[email protected]", "address": { "street": "123 Main St", "city": "San Francisco", "state": "CA", "postalCode": "12345", "country": "United States" }, "totalPurchaseAmt": 36000 }
- Install the v3 version of the Fauna CLI:
npm install -g fauna-shell@3
- Start Fauna in a container:
docker run --rm --name fauna -p 8443:8443 -p 8084:8084 fauna/faunadb
- Configure the schema:
./setup-local.sh
- Run tests:
dotnet test
- Start Fauna in a container:
docker run --rm --name fauna -p 8443:8443 -p 8084:8084 fauna/faunadb
- Configure the schema:
./setup-local.sh
- Copy the secret returned from running
./setup-local.sh
cd DotNetSampleApp
FAUNA_SECRET="<SECRET>" FAUNA_ENDPOINT="http://localhost:8443" dotnet run