Skip to content

Learn Fauna database fundamentals with Fauna Query Language (FQL) v10 and the .NET driver.

Notifications You must be signed in to change notification settings

fauna/dotnet-sample-app

Repository files navigation

Fauna .NET sample app

Overview

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.

Highlights

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's total 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 validate status transitions for orders.

Requirements

To run the app, you'll need:

You should also be familiar with basic Fauna CLI commands and usage. For an overview, see the Fauna CLI docs.

Setup

  1. Clone the repo and navigate to the dotnet-sample-app directory:

    git clone [email protected]:fauna/dotnet-sample-app.git
    cd dotnet-sample-app
  2. 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, use cloud-us.

    The command requires an email and password login. If you log in to Fauna using GitHub or Netlify, you can enable email and password login using the Forgot Password workflow.

  3. Use the Fauna CLI to create the EcommerceDotnet database:

    fauna create-database EcommerceDotnet
  4. 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.
    • EcommerceDotnet as the database.
  5. Push the .fsl files in the schema directory to the EcommerceDotnet database:

    fauna schema push

    When prompted, accept and stage the schema.

  6. Check the status of the staged schema:

    fauna schema status
  7. 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 the schema directory.

  8. Create a key with the server role for the EcommerceDotnet database:

    fauna create-key --environment='' EcommerceDotnet server

    Copy the returned secret. The app can use the key's secret to authenticate requests to the database.

  9. Make a copy of the .env.example file and name the copy .env. For example:

    cp .env.example .env
  10. In .env, set the FAUNA_SECRET environment variable to the secret you copied earlier:

    ...
    FAUNA_SECRET=fn...
    ...
    

Run the app

The app runs an HTTP API server. From the sample-app directory, run:

export $(grep -v '^#' .env | xargs) && \
FAUNA_SECRET=$FAUNA_SECRET dotnet run

Once started, the local server is available at http://localhost:5049.

Docker

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.

Sample data

The app includes seed data that's populated when you make a successful request to any API endpoint.

HTTP API endpoints

The app's HTTP API endpoints are defined in the sample-app/Controllers directory.

An OpenAPI spec and Swagger UI docs for the endpoints are available at:

Make API requests

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 .

Expand the app

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:

  1. If the app server is running, stop the server by pressing Ctrl+C.

  2. In schema/collections.fsl, add the following totalPurchaseAmt computed field definition to the Customer 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) => {
    +   sum + order.total
    + }))
      ...
    }
    ...

    Save schema/collections.fsl.

  3. In sample-app/Controllers/QuerySnippets.cs, add the totalPurchaseAmt field to the CustomerResponse method's projection:

    ...
    customer {
        id,
        name,
        email,
    +   address,
    +   totalPurchaseAmt
    }
    ...
  4. Push the updated schema to the EcommerceDotnet database:

    fauna schema push

    When prompted, accept and stage the schema.

  5. Check the status of the staged schema:

    fauna schema status
  6. When the status is ready, commit the staged schema changes to the database:

    fauna schema commit
  7. In sample-app/Models/Customer.cs, add the totalPurchaseAmt field to the Customer 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 sample-app/Models/Customer.cs.

    Customer-related endpoints use this template to project Customer document fields in responses.

  8. 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
  9. 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
    }

Development

Local Testing

  1. Install the latest Fauna CLI: npm install -g fauna-shell
  2. Start Fauna in a container: docker run --rm --name fauna -p 8443:8443 -p 8084:8084 fauna/faunadb
  3. Configure the schema: ./setup-local.sh
  4. Run tests: dotnet test

dotnet run with local Fauna

  1. Start Fauna in a container: docker run --rm --name fauna -p 8443:8443 -p 8084:8084 fauna/faunadb
  2. Configure the schema: ./setup-local.sh
  3. Copy the secret returned from running ./setup-local.sh
  4. cd DotNetSampleApp
  5. FAUNA_SECRET="<SECRET>" FAUNA_ENDPOINT="http://localhost:8443" dotnet run

About

Learn Fauna database fundamentals with Fauna Query Language (FQL) v10 and the .NET driver.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Contributors 3

  •  
  •  
  •