Skip to content

An example application which showcases how to create a simple CRUD REST service backed by FaunaDB

Notifications You must be signed in to change notification settings

lregnier/faunadb-demo-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FaunaDB Demo App

This is a demo application which showcases how to create a simple CRUD REST service backed by FaunaDB. The examples presented in the Getting Started and CRUD guides have been used as starting point for implementing the service.

Table of Contents

Prerequisites

1. Setup a Fauna Cloud account

Create a Fauna Cloud account filling the form here.

2. Install Fauna Shell

Open a terminal and install the Fauna Shell. If you are on a PC, you can use npm:

$ npm install -g fauna-shell

Alternatively, if you are on a Mac, you can use Homebrew:

$ brew install fauna-shell

3. Create Database

Next, create a new database to which the application will connect to for storing the data. For doing so, login to your Fauna Cloud account from the Fauna Shell by typing the following command:

$ fauna cloud-login

It will prompt for your Fauna Cloud credentials, where you need to enter the email you used for signing up, and your password.

Email: email@example.com
Password: **********

Note: once you are logged in on a machine, the Fauna Shell will remember your credentials so you don’t need to log in again.

The next step will be to create the database. Issue the following command for creating a database called demo-app:

$ fauna create-database demo-app

4. Set up Schema

Run below command for creating the DB schema. It will execute all required queries from a file.

$ fauna run-queries demo-app --file=./scripts/create_schema.fql

5. Obtain an API Key

Next, issue an API Key for connecting to the new created DB from the service. Execute below command for doing so:

$ fauna create-key demo-app server

Make sure to write down the given secret key. It will be used for starting up the service later on.

Alternatively, you can also create an API Key from the Cloud Dashboard here.

Running the app

For starting up the service you can use all sbt standard commands. If you don't have sbt installed, follow instructions here.

Before runnning the service, make sure to include the API key created above as follows:

$ sbt run -Dfauna-db.secret=your_api_key_goes_here

The app will start by default at port 9000.

API Reference

Create a Post

Creates a new Post with an autogenerated Id.

Request

POST /posts
Content-type: application/json
{
  "title": "My cat and other marvels",
  "tags": ["pet", "cute"]
}

curl example
$ curl -XPOST -H "Content-type: application/json" -d '{
  "title": "My cat and other marvels",
  "tags": ["pet", "cute"]
}' 'http://localhost:9000/posts'

Response

Status: 201 - Created
Content-type: application/json
{
  "id": "219871526709625348",
  "title": "My cat and other marvels",
  "tags": ["pet", "cute"]
}

Create several Posts

Creates several Posts within a single requests. The Posts will be persisted in a single transaction as well.

Request

POST /posts
Content-type: application/json
[
  {"title": "My cat and other marvels", "tags": ["pet", "cute"]},
  {"title": "Pondering during a commute", "tags": ["commuting"]},
  {"title": "Deep meanings in a latte", "tags": ["coffee"]}
]
curl example
$ curl -XPOST -H "Content-type: application/json" -d '[
  {"title": "My cat and other marvels", "tags": ["pet", "cute"]},
  {"title": "Pondering during a commute", "tags": ["commuting"]},
  {"title": "Deep meanings in a latte", "tags": ["coffee"]}
]' 'http://localhost:9000/posts'

Response

Status: 200 - OK
Content-type: application/json
[
  {
    "id": "219970669169869319",
    "title": "My cat and other marvels",
    "tags": ["pet", "cute"]
  },
  {
    "id": "219970865138237959",
    "title": "Pondering during a commute",
    "tags": ["commuting"]
  },
  {
    "id": "219970873639043587",
    "title": "Deep meanings in a latte",
    "tags": ["coffee"]
  }
]

Retrieve a Post

Retrieves an existent Post for the given Id. If the Post cannot be found, a 404 - Not Found response is returned.

Request

GET /posts/{post_id}
curl example
$ curl -XGET 'http://localhost:9000/posts/219871526709625348'

Response

Status: 200 - OK
Content-type: application/json
{
  "id": "219871526709625348",
  "title": "My cat and other marvels",
  "tags": ["pet", "cute"]
}

Retrieve Posts

Retrieves all existent Posts.

Request

GET /posts
curl example
$ curl -XGET 'http://localhost:9000/posts'

Response

Status: 200 - OK
Content-type: application/json
[
  {
    "id": "219970669169869319",
    "title": "My cat and other marvels",
    "tags": ["pet", "cute"]
  },
  {
    "id": "219970865138237959",
    "title": "Pondering during a commute",
    "tags": ["commuting"]
  },
  {
    "id": "219970873639043587",
    "title": "Deep meanings in a latte",
    "tags": ["coffee"]
  }
]

Retrieve Posts by Title

Retrieves all the existent Posts matching the given Title.

Request

GET /posts?title={post_title}

Response

Content-type: application/json
[
  {
    "id": "219970669169869319",
    "title": "My cat and other marvels",
    "tags": ["pet", "cute"]
  }
]
curl example
$ curl -XGET 'http://localhost:9000/posts?title=My%20cat%20and%20other%20marvels'

Replace a Post

It replaces an existent Post for the given Id with given fields. All fields should be provided in the representation along the request. If optional fields are not provided they will be set as empty. If the Post cannot be found, a 404 - Not Found response is returned.

Request

PUT /posts/{post_id}
Content-type: application/json
{
  "title": "My dog and other marvels"
}
curl example
$ curl -XPUT -H "Content-type: application/json" -d '{
  "title": "My dog and other marvels"
}' 'http://localhost:9000/posts/219871526709625348'

Response

Status: 200 - OK
Content-type: application/json
{
  "id": "219871526709625348"
  "title": "My dog and other marvels",
  "tags": []
}

INFO: note that as the 'tags' field has not been provided in the request, it has been set as empty.

Delete a Post

Deletes an existent Post for the given Id. If the Post cannot be found, a 404 - Not Found response is returned.

Request

DELETE /posts/{post_id}
curl
$ curl -XDELETE 'http://localhost:9000/posts/219871526709625348'

Response

Status: 200 - OK
Content-type: application/json
{
  "id": "219871526709625348",
  "title": "My cat and other marvels",
  "tags": ["pet", "cute"]
}

FQL Reference

The persistence layer has been modeled after Domain-Driven Design Repository pattern.

A word on the Repository pattern...

Unlike DAOs, which are designed following a data access orientation, Repositories are implemented following a collection orientation. This means that their interface will mimic the one of a collection of objects rather than exposing a set of CRUD operations. The focus is put this way on the domain as a model rather than on data and any CRUD operations that may be used behind the scenes to manage the actual persistence.

Save a Post

If there's no previous Post for the given Id, it creates a new Post using an autogenerated Id and the given data. If there's a Post for the given Id, it replaces its content with the given data.

Select(
  "data",
  If(
    Exists(Ref(Class("posts"), "1520225686617873")),
    Replace(
      Ref(Class("posts"), "1520225686617873"), 
      Obj("data" -> Obj("title" -> "My cat and other marvels")))
    )
    Create(
      Ref(Class("posts"), "1520225686617873"), 
      Obj("data" -> Obj("title" -> "My cat and other marvels"))))
    )
  )  
)

References:

Save several Posts

It saves several Posts within a single transaction. It uses the Map function to iterate over a collection of entities and apply the above save query to them.

Map(
  Arr(Obj("data" -> Obj("title" -> "My cat and other marvels")))),
  Lambda( nextEntity => 
    //-- Save Query goes here
  )

References:

Find a Post

It looks up a Post by its Id and returns its data back.

Select(
  "data", 
  Get(Ref(Class("posts"), "1520225686617873"))
)

References:

Find all Posts

It looks up all Posts in the class and returns its data back. First, all Posts Ids are found using the class Index together with the Paginate function and then its data is looked up through the Get function.

SelectAll(
  "data",
  Map(
    Paginate(Match(Index("all_posts"))),
    Lambda( nextRef => 
      Select("data", Get(nextRef)))
  )
)

References:

Find Posts by Title

It looks up all Posts matching the given Title and returns its data. The search is done using a previsouly created Index. First, all Posts Ids are found using the Index together with the Paginate function and then its data is looked up through the Get function.

SelectAll(
  "data",
  Map(
    Paginate(Match(Index(posts_by_title)), "My cat and other marvels"),
    Lambda( nextRef => 
      Select("data", Get(nextRef)))
  )
)

References:

Remove a Post

It removes the Post for the given Id if any and returns its data.

Select(
  "data",
  Delete(Ref(Class("posts"), "1520225686617873"))
)

References:

About

An example application which showcases how to create a simple CRUD REST service backed by FaunaDB

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages