How To Build REST APIs With Golang And Fauna

Tags: fauna, go, webdev, beginners
Published: 2021-12-08 06:08:37


# Introduction

Golang has become very popular nowadays. It’s fast, has an easy-to-learn syntax, and is gaining ground among backend developers. Today, we will learn how to use Golang to perform Create, Read, Update, and Delete (CRUD) operations against an equally popular database, Fauna.

[Fauna](https://fauna.com/?utm_source=DevTo&utm_medium=referral&utm_campaign=WritewithFauna_GolangREST_Fesse) is a flexible, developer-friendly, transactional cloud database delivered as a secure Data API that provides two interfaces: GraphQL and the Fauna Query Language (FQL). Fauna is a unique indexed document system that supports relations, documents, and graphs for unmatched modeling flexibility. It includes functionality to store collections, indexes, and other databases (multi-tenancy). To learn more about Fauna, visit the [official documentation](https://docs.fauna.com/fauna/current/start/index.html?utm_source=DevTo&utm_medium=referral&utm_campaign=WritewithFauna_GolangREST_Fesse). [Fauna](https://fauna.com/?utm_source=DevTo&utm_medium=referral&utm_campaign=WritewithFauna_GolangREST_Fesse) uses a pre-existing infrastructure to build web applications without usually setting up a custom API server. This efficiently helps to save time for developers, and the stress of choosing regions and configuring storage that exists among other databases. All maintenance we need is actively taken care of by engineers and automated DevOps at Fauna.

Here’s the [full code](https://github.com/IkehAkinyemi/faunaDB-golang) of the project we would build in this tutorial. And throughout the tutorial, we’ll modularize the different API routes defined within the project. This will help us test out the different API request without it being dependent.


# Initial setup

Let’s set up our development environment. First, we will need to install Golang because that is the language we will be using here. Click this [link to learn how to install it for your operating system](https://golang.org/doc/install).
Next, we need to create an account on the Fauna either through the dashboard UI or through `fauna-shell` CLI. For this tutorial, we’ll make use of the dashboard to setup and interact with our database. Follow this [link](https://fauna.com/https://dashboard.fauna.com/accounts/register?utm_source=DevTo&utm_medium=referral&utm_campaign=WritewithFauna_GolangREST_Fesse) to create an account. Then create your first database and navigate to the **Security** webpage by clicking on the **Security** link on the sidebar to generate an API key for our application. Fill the input field and click the `SAVE` button.


![SECRET API key](https://paper-attachments.dropbox.com/s_E60027E445A7458A172C34FC7BE2876075869582DC96788EE86253E537C82054_1638942715559_Screenshot+2021-12-08+at+06.51.41.png)

> N.B., make sure you take note of your connection string, especially the Secret API key, as it is only shown once. This secret won't be displayed again, so please copy and save it somewhere safe. This tutorial also assumes you have some knowledge of programming with [Golang](https://golang.org/).

Next, let’s jump into building the different parts of our application.

# Project overview

For the project, we’ll build the REST API that allows us to make API request to create, read, update, and delete items from the Fauna database. We’ll build a Blog-like platform, where we can create, retrieve, update and delete a post from the application. We’ll use [Postman](https://www.postman.com/) to make API requests to the server that we’ll setup up with Golang.


## Setup Local Environment

Let’s start with creating our root folder within the Golang `GOPATH` at the root directory of your local machine, `$HOME/go/src/`. The default `$GOPATH` on Unix is `$HOME/go`. We'll store our programs there.


    mkdir faunadb-go
    cd faunadb-go

Now, let’s start with initializing and adding the go-modules required for our application by using the `go get` command. Let install the Fauna’s open source Go driver, which provides the resources required to interact with Fauna, and also build the REST API using the `**gorilla/mux**` router instead of the traditional `**net/http**` router.


    go get github.com/fauna/faunadb-go/v5/faunadb
    go get github.com/gorilla/mux


> Please note that the driver undergoes breaking changes from time to time. It is recommended to use one of the following methods instead:

**JSON**
For the purpose of this tutorial I’ll be using JavaScript Object Notation as a means of sending and receiving all information and thankfully Go comes with some excellent support for encoding and decoding these formats using the standard library package, encoding/json.

**Marshalling**
There’s a good support within Golang to easily convert data structures in GO into JSON by using something called marshalling which produces a byte slice containing a very long string with no extraneous white space.


## Setup a server to handle HTTP requests

To setup a server using Golang, we’ll first create a new file called `**main.go**`. Within this `**main.go**` file we’ll want to define 3 different functions. A `**homePage**` function that will handle all requests to our root URL, a `**handleRequests**` function that will match the URL path hit with a defined function and a `**main**` function which will act as the default entrance into our REST API.


    package main
    
    import (
      "fmt"
      "net/http"
    
      f "github.com/fauna/faunadb-go/faunadb"
      "github.com/gorilla/mux"
    )
    
    var client = f.NewFaunaClient(os.Getenv("FAUNADB_SECRET_KEY"))
    // Create a class to store Blog
    _, _ = client.Query(f.CreateCollection(f.Obj{"name": "Blog"}))
    
    func homePage(w http.ResponseWriter, r *http.Request) {
      fmt.Fprintf(w, "Welcome to REST API with FaunaDB")
      fmt.Println("We've reached the Home page endpoint!")
    }
    
    func handleRequests() {
      r := mux.NewRouter().StrictSlash(true)
      r.HandleFunc("/", homePage)
    
      log.Fatal(http.ListenAndServe(":10000", r))
    }
    
    func main() {
      handleRequests()
    }
    

 
 Now, let run the Go program using the `go run` command in the terminal as below:
 

    go run main.go

Let’s open Postman to test that our server is actually listening for incoming requests. Now, make a **GET** request to the **localhost:10000/** URL to hit call the `homePage` function:


![API request-response on localhost:10000](https://paper-attachments.dropbox.com/s_E60027E445A7458A172C34FC7BE2876075869582DC96788EE86253E537C82054_1637241328983_faunadb-go-1.png)



## Create a Fauna collection instance

Here, we’ll create a route to create a collection on Fauna. Within this collection, we’ll create a Document. To create new documents in a Fauna collection, we’ll first make a connection to the database using the client provided by Fauna, then use the `Create` method that allows us to insert a single document into our database. We named our **Document** `Blog` in this tutorial


    func createNewPost(w http.ResponseWriter, r *http.Request) {
      req, _ := ioutil.ReadAll(r.Body)
      var post Post
      json.Unmarshal(req, &post)
      // Save post at FaunaDB
      newProfile, _ := client.Query(
        f.Create(
          f.Collection("Blog"),
          f.Obj{"data": post},
        ),
      )
      // Get generated post ID
      _ = newProfile.At(ref).Get(&postId)
      Blog = append(Blog, post)
      json.NewEncoder(w).Encode(post)
    }

Next, let’s update the `handleRequests` function, defining a new route to handle the `createNewPost` function:


    func handleRequests() {
      r := mux.NewRouter().StrictSlash(true)
      r.HandleFunc("/", homePage)
      r.HandleFunc("/blog/post", createNewPost)
    
      log.Fatal(http.ListenAndServe(":10000", r))
    }

Let’s open Postman to test that our server is actually listening for incoming requests. Now, make a **POST** request to the **localhost:10000/blog/post** URL to hit call the `createNewPost` function:


![Create a new post and stored it on DB](https://paper-attachments.dropbox.com/s_E60027E445A7458A172C34FC7BE2876075869582DC96788EE86253E537C82054_1637276430301_faunadb-go-2.png)


Next, let’s navigate to our database to confirm that our **Document** was successfully created on the database.


![Confirmed the Document (Post) was created on the DB](https://paper-attachments.dropbox.com/s_E60027E445A7458A172C34FC7BE2876075869582DC96788EE86253E537C82054_1637276791578_faunadb-go-3.png)



## Retrieve a Document from Fauna collection instance

We’ll define a `gorilla/mux` route which will allow us to easily do things such as retrieve path based on the current value of query parameter, `var postId f.RefV` in this tutorial.


    func getSinglePost(w http.ResponseWriter, r *http.Request) {
      req, _ := ioutil.ReadAll(r.Body)
      var post Post
      json.Unmarshal(req, &post)
      // Retrieve post by its ID
      value, _ := client.Query(f.Get(postId))
      _ = value.At(data).Get(&post)
      json.NewEncoder(w).Encode(value)
    }

In the above code, we’ll use the `json` to parse the `value` from the call of `f.Get()` method as we pass in the `postId` into it. Next, let’s update the `handleRequests` function, defining a new route to handle the `getSinglePost` function:


    func handleRequests() {
      r := mux.NewRouter().StrictSlash(true)
      r.HandleFunc("/", homePage)
      r.HandleFunc("/blog/post", createNewPost)
      r.HandleFunc("/blog", getSinglePost).Methods("GET")
    
      log.Fatal(http.ListenAndServe(":10000", r))
    }

Let’s open Postman to test that our server is actually listening for incoming requests. Now, make a **GET** request to the **localhost:10000/blog/post** URL to hit call the `getSinglePost` function:


![Retrieves Document (Post) from the Db using a ref.](https://paper-attachments.dropbox.com/s_E60027E445A7458A172C34FC7BE2876075869582DC96788EE86253E537C82054_1637278534031_faunadb-go-4.png)



## Update a Document from Faunacollection instance

Fauna provides the `f.Update` operation to change documents in a collection. `f.Update` function changes the specified fields or overwrites existing data with new fields you provided in a document.


    func updatePost(w http.ResponseWriter, r *http.Request) {
      // Update existing post entry
      _, _ = client.Query(
        f.Update(
          postId,
          f.Obj{"data": f.Obj{
            "Title": "Adieu to Fauna blog posts", "Content": "In the next article, we'll build a simple micro-service", "Summary": "This article featured Golang architectures",
          }},
        ),
      )
    }

In the above code, we hardcoded our update using the `f.Obj`, `Obj` is a expression shortcut to represent any valid JSON object. Next, let’s update the `handleRequests` function, defining a new route to handle the `updatePost` function:


    func handleRequests() {
      r := mux.NewRouter().StrictSlash(true)
      r.HandleFunc("/", homePage)
      r.HandleFunc("/blog/post", createNewPost)
      r.HandleFunc("/blog", getSinglePost).Methods("GET")
      r.HandleFunc("/blog", updatePost).Methods("PUT")
    
      log.Fatal(http.ListenAndServe(":10000", r))
    }

Let’s open Postman to test that our server is actually listening for incoming requests. Now, make a **GET** request to the **localhost:10000/blog/post** URL to hit call the `updatePost` function. Once we’ve made the API request through Postman, let’s navigate to our database to confirm that our **Document** was successfully updated on the database.


![Updated Document (Post) in the DB](https://paper-attachments.dropbox.com/s_E60027E445A7458A172C34FC7BE2876075869582DC96788EE86253E537C82054_1637281246597_faunadb-go-5.png)



## Delete a Document from Fauna collection instance

We’ll always at a point need to delete the data being exposed by your REST API. In order to do this, you need to expose a `**DELETE**` endpoint within our API route that will make request to the database to delete whatever is associated with that identifier.
In this section of this tutorial, you are going to be creating another endpoint which receives `**HTTP DELETE**` requests and deletes a post if they match the given `ref` parameter.


    func deletePost(w http.ResponseWriter, r *http.Request) {
      // Delete post using its ID
      _, _ = client.Query(f.Delete(postId))
    }

With the `f.Delete()` will delete a particular **Document** from the `**Blog**` collection within our database. Next, let’s update the `handleRequests` function, defining a new route to handle the `deletePost` function:


    func handleRequests() {
      r := mux.NewRouter().StrictSlash(true)
      r.HandleFunc("/", homePage)
      r.HandleFunc("/blog", getSinglePost).Methods("GET")
      r.HandleFunc("/blog/post", createNewPost)
      r.HandleFunc("/blog", deletePost).Methods("DELETE")
      r.HandleFunc("/blog", updatePost).Methods("PUT")
    
      log.Fatal(http.ListenAndServe(":10000", r))
    }

Now, let’s make a **DELETE** request to the **localhost:10000/blog/post** URL to hit call the `updatePost` function on Postman. Once we’ve made the API request through Postman, let’s navigate to our database to confirm that our **Document** was successfully deleted from the database:


![alt text](https://paper-attachments.dropbox.com/s_E60027E445A7458A172C34FC7BE2876075869582DC96788EE86253E537C82054_1637287824422_faunadb-go-6.png)


Now our **COLLECTION**  on the database is empty as we have deleted all the posts from the database.


# Conclusion

I hope this was helpful to guide you through what could be considered often to be a challenging task. The lack of straightforward resources on using Fauna with Go requires developers to spend a lot of time exploring documentation. With this article as a reference guide, you can confidently integrate Fauna into a Go application.
You can head over to the official [Fauna](https://fauna.com/?utm_source=DevTo&utm_medium=referral&utm_campaign=WritewithFauna_GolangREST_Fesse) and [Go driver documentation](https://pkg.go.dev/github.com/fauna/faunadb-go/faunadb#Select) to explore more functionalities that Fauna provides.