DEV Community

FesserBlondie
FesserBlondie

Posted on • Edited on

How To Build REST APIs With Golang And Fauna

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 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. Fauna 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 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.
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 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

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.

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 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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()
}
Enter fullscreen mode Exit fullscreen mode

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

go run main.go
Enter fullscreen mode Exit fullscreen mode

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

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)
}
Enter fullscreen mode Exit fullscreen mode

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))
}
Enter fullscreen mode Exit fullscreen mode

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

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

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)
}
Enter fullscreen mode Exit fullscreen mode

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))
}
Enter fullscreen mode Exit fullscreen mode

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.

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",
      }},
    ),
  )
}
Enter fullscreen mode Exit fullscreen mode

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))
}
Enter fullscreen mode Exit fullscreen mode

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

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))
}
Enter fullscreen mode Exit fullscreen mode

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))
}
Enter fullscreen mode Exit fullscreen mode

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

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 and Go driver documentation to explore more functionalities that Fauna provides.

Top comments (0)