Supercharge Go APIs with Serverless Functions
Tags: go, serverless, gingonic
Published: 2022-11-24 07:31:56

---
title: Supercharge Go APIs with Serverless Functions
published: true
description: Learn how to use Serverless Functions to build a user management API in Go using Netlify, Xata, and Cloudinary.
tags: #golang #go #serverless #ginGonic
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qe8psbzbg4pvkb6tex4w.png
# Use a ratio of 100:42 for best results.
# published_at: 2022-11-23 21:07 +0000
---
Serverless Function is a single-purpose programming feature that allows developers to write and deploy software without purchasing and maintaining servers. It lets developers focus on the core business logic of their application without worrying about logistics, operation, and infrastructure associated with software development.

In this post, we will learn how to use Serverless Functions to build a user management API in Go using Netlify, Xata, and Cloudinary.

## Technology overview

[Netlify](https://www.netlify.com/) is a platform for deploying and building highly-performant and dynamic websites, e-commerce stores, and web applications.

[Xata](https://xata.io/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) is an HTTP API-based serverless database for building scalable applications. It supports a built-in search engine, branching, scalability, and durability without manually managing database configuration and deployment.

[Cloudinary](https://cloudinary.com/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) is a visual media service for uploading, storing, managing, transforming, and delivering images and videos for websites and applications. 

## GitHub links

The project source codes are below:

- [Serverless Functions source code](https://github.com/Mr-Malomz/xata-functions)
- [Go API](https://github.com/Mr-Malomz/go-user-service)

## Prerequisites 

To follow along with this tutorial, the following requirements apply:

- Basic understanding of Go
- Basic understanding of JavaScript
- [Node.js](https://nodejs.org/en/) installed
- A [Netlify](https://www.netlify.com) account for deploying Serverless Functions. [**Signup**](https://app.netlify.com/signup?_ga=2.194596141.1083651187.1647633137-873794739.1647633137) **is completely free**
- A [Xata account](https://xata.io/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) for storing data. [**Signup**](https://app.xata.io/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) **is completely free**
- A [Cloudinary account](https://cloudinary.com/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) for image optimization. [**Signup**](https://cloudinary.com/users/register/free?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) **is completely free**.
- A [Github account](https://github.com) for saving source code. [**Signup**](https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F&source=header-home) **is completely free**.
## Set up a Database on Xata

To create a database for storing our user management API’s data, we need to log into our Xata’s workspace, click the **Add a Database** button, input `users` as the database name, and **Create**.

![Add a Database](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667173516275_Screenshot+2022-10-31+at+00.44.55.png)
![input database name](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667173605124_Screenshot+2022-10-29+at+16.28.50.png)


Next, we need to create a table in our database. To do this, click the **Start from scratch** menu, input `userDetails` as the table name, and **Add table**.

![click the start from scratch](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667173724094_Screenshot+2022-10-29+at+16.30.08.png)
![input and create](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667173928867_Screenshot+2022-10-29+at+16.30.43.png)


**PS**: *Xata auto-generates an ID column (a unique identifier) for our table.*

With that done, we need to add a `firstName`, `lastName`, `phoneNumber`, and `avatar` columns to our table. To do this, click on the **Plus icon**, select **String**, input column name, and **Create column**.

![plus icon](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667174472120_Screenshot+2022-10-29+at+16.31.54.png)
![select string](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667174472131_Screenshot+2022-10-31+at+01.00.47.png)
![input name](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667174553609_Screenshot+2022-10-31+at+01.02.02.png)


After creating the columns, our updated table should be similar to the screenshot below:

![updated table](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667174730823_Screenshot+2022-10-31+at+01.05.15.png)


**Get Database URL and set up API Key**
By default, Xata provides a unique and secure URL for accessing the database. To get our database URL, click the **Get code snippet** button, copy the URL, and then click the **Set up API key** button to generate API key. 

![Get code snippet](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667175618565_Screenshot+2022-10-31+at+01.13.20.png)



![URL and Set up API key](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667175618585_Screenshot+2022-10-29+at+16.40.21.png)


**PS**: *The URL we need to copy starts from the* `*https://……*` *section*

Click the **Add a key** button, input `xata-function` as the name, and **Save**.

![Add a key](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667175790072_Screenshot+2022-10-29+at+16.42.41.png)
![Copy API Key](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667175790087_Screenshot+2022-10-29+at+16.46.22.png)


We must copy and keep the URL and generated API key, as they will come in handy when building our serverless functions.

## Image sourcing and upload to Cloudinary

Next, we need to upload an image we will use as a default avatar when creating a user. 

**Avatar url**

- bit.ly/3gUBL7E

In our Cloudinary dashboard, we uploaded the image by clicking on the **Media Library** tab, clicking on **Upload**, selecting the **Web Address** option, inputting the **URL**, and clicking on the **Arrow Button** to upload.

![Cloudinary console and upload button for other formats of upload](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667176524103_Screenshot+2022-10-31+at+01.34.28.png)

![select web address and enter url](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667176648327_Screenshot+2022-10-31+at+01.36.43.png)


After uploading the image, we will see it displayed on the console. To get the image URL, mouse hover on the image and click on the **Copy URL** icon. The URL will come in handy when building our Serverless Functions.

![copy url](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667176777775_Screenshot+2022-10-30+at+00.29.58.png)

## Creating Serverless Functions

To get started, we need to navigate to the desired directory and run the command below:

```bash
mkdir xata-functions && cd xata-functions
```

The command creates a directory called `xata-functions` and navigates into it.

**Initializing project and installing dependencies**
First, we need to initialize an empty Node.js project by running the command below:

```bash
npm init -y
```

Lastly, we need to install `node-fetch`, a package for making HTTP requests. To do this, we need to run the command below:

```bash
npm i node-fetch
```

**Adding logics to the Serverless Functions**
With that done, we can start creating our application logic. To get started; first, we need to create a `netlify` folder and create a `functions` folder in this folder.


![updated folder structure](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667247928234_Screenshot+2022-10-31+at+21.25.15.png)


Secondly, we need to create a `create.js` file inside the `functions` folder and add the snippet below:

```js
import fetch from 'node-fetch';

exports.handler = async function (event, context, callback) {
    let bodyRequest = JSON.parse(event.body);
    const body = {
        firstName: bodyRequest.firstName,
        lastName: bodyRequest.lastName,
        phoneNumber: bodyRequest.phoneNumber,
        avatar: 'https://res.cloudinary.com/dtgbzmpca/image/upload/v1667083687/abstract-user-flat-4.png',
    };

    const response = await fetch(
        `${process.env.XATA_URL}:main/tables/userDetails/data`,
        {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                Authorization: `Bearer ${process.env.XATA_API_KEY}`,
            },
            body: JSON.stringify(body),
        }
    );
    const data = await response.json();

    return {
        statusCode: 200,
        body: JSON.stringify(data),
    };
};
```

The snippet above does the following:

- Imports the required dependency 
- Gets the request body
- Uses the request body to create a `body` object by passing in the `firstName`, `lastName`, `phoneNumber`, and `avatar` default URL we got from Cloudinary
- Creates a `POST` request to the Xata database by passing the URL as an environment variable with the database details and API key
- Returns the appropriate response.

We also constructed the Xata database URL by passing in the **branch**, **table name**, and **endpoint type**.

```bash
https://sample-databaseurl/users:<BRANCH NAME>/tables/<TABLE NAME>/ENDPOINT TYPE
```

We can get the required details from our workspace

![Branch name and Table name](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667251155158_Screenshot+2022-10-29+at+17.40.43.png)


In our case, we filled it using an environment variable. We will add it when deploying our application to Netlify. An adequately filled  URL is below:

```bash
https://sample-databaseurl/users:main/tables/userDetails/data
```

Thirdly, we need to create a `get.js` file inside the same `functions` folder and add the snippet below:

```js
import fetch from 'node-fetch';

exports.handler = async function () {
    const body = {
        page: {
            size: 15,
        },
    };

    const response = await fetch(
        `${process.env.XATA_URL}:main/tables/userDetails/query`,
        {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                Authorization: `Bearer ${process.env.XATA_API_KEY}`,
            },
            body: JSON.stringify(body),
        }
    );
    const data = await response.json();

    return {
        statusCode: 200,
        body: JSON.stringify(data),
    };
};
```

The snippet above works similarly to the `create.js` file. However, we created a `body` object to paginate the requested data from the Xata database.

Lastly, we need to add a deployment file that instructs Netlify to build our application effectively. To do this, we need to create a `netlify.toml` file in the root directory of our project and add the snippet below:

```toml
[functions]
  node_bundler = "esbuild"
```

**Pushing our source code to GitHub**
To enable a seamless deployment process, we need to push our source code to GitHub. To get started, we need to log into our GitHub account, create a repository, input `xata-functions` as the name and **Create repository**.

Next, we initialize a `git` project and save recent changes in our project by running the command below:

```bash
git init
git add .
git commit -m "add serverless functions"
```

To push our changes, copy and run the highlighted commands on the terminal:

![Push changes to GitHub](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667252593439_Screenshot+2022-10-29+at+17.46.07.png)



## Deploying to Netlify

To get started, we need to log into our [Netlify](https://app.netlify.com/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) dashboard. Click on **Add new site** dropdown and select  **Import an existing project**.

![Create site](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667252724024_Screenshot+2022-10-29+at+19.48.13.png)


Select **GitHub** as the Git provider and authorize Netlify. 

![select Github](https://paper-attachments.dropboxusercontent.com/s_8D31A8FC979E5F8A04C65B533C8604145C4DC40C7A1F1BAA5C7B6711437D62F0_1647646116402_Screenshot+2022-03-19+at+00.27.32.png)


Search for `xata-function` and select the repository.

![select repository](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667252806071_Screenshot+2022-10-29+at+19.49.43.png)


Click on **Show advanced**, click the **New variable** button and add the `XATA_URL` and `XATA_API_KEY` environment variables as key and their corresponding values.

![Show advanced](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667253099549_Screenshot+2022-10-29+at+19.50.21.png)
![input env variable](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667253143824_Screenshot+2022-10-29+at+19.51.23.png)


As earlier mentioned, we can get Xata’s URL and API key from our workspace.


![URL](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667253588412_Screenshot+2022-10-31+at+22.56.31.png)
![API KEY](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667253588385_Screenshot+2022-10-29+at+16.46.22.png)


Click on **Deploy site** button to start deployment. It might take a few minutes.

We can view and get our deployed Serverless Functions URL by navigating to the **Functions** tab, and click on any of the functions to access the URL.

![Deployed Functions](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667253769845_Screenshot+2022-10-29+at+19.00.57.png)
![Copy Function URL](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667253769874_Screenshot+2022-10-29+at+19.01.28.png)



## Leveraging the Serverless Functions to build Go APIs

With our Serverless Functions up and running, we can start leveraging them to build our user management APIs. To get started, we need to navigate to the desired directory and run the command below in our terminal:

```bash
mkdir go-user-service && cd go-user-service
```

This command creates a  `go-user-service` and navigates into the project directory.

Next, we need to initialize a Go module to manage project dependencies by running the command below:

```bash
go mod init go-user-service
```

This command will create a `go.mod` file for tracking project dependencies.

We proceed to install the required dependencies with:

```bash
go get github.com/gin-gonic/gin github.com/go-playground/validator/v10
```

`github.com/gin-gonic/gin` is a framework for building web applications. 

`github.com/go-playground/validator/v10` is a library for validating structs and fields.

**Structuring our application**
It is essential to have a good project structure as it makes the project maintainable and easier for us and others to read our codebase.
To do this, we need to create an `api`, `cmd`, and `data` folder in our project directory.

![project directory](https://paper-attachments.dropboxusercontent.com/s_5069C6F392C7917E74EFE05A44CB40043929A36F87C7D7DD3BE0A101A2DF97B2_1667341979726_Screenshot+2022-11-01+at+23.32.39.png)


`api` is for structuring our API-related files

`cmd` is for structuring our application entry point

`data` is for structuring our application data

**Create the API models**
Next, we need to create models to represent our application data. To do this, we need to navigate to the `data` folder and, in this folder, create a `model.go` file and add the snippet below:

```go
package data

type User struct {
    Id          string `json:"id,omitempty"`
    FirstName   string `json:"firstName,omitempty" validate:"required"`
    LastName    string `json:"lastName,omitempty" validate:"required"`
    PhoneNumber string `json:"phoneNumber,omitempty" validate:"required"`
    Avatar      string `json:"avatar,omitempty"`
}

type Records struct {
    Records []User `json:"records,omitempty" validate:"required"`
}

type CreateResponse struct {
    Id string `json:"id,omitempty" validate:"required"`
}
```

The snippet above creates a `User`, `Records`, and `CreateResponse` struct with the required properties to describe requests and response type.

**Create the API routes, helpers, service, and handlers**
With the models fully set up, we need to navigate to the `api` folder and do the following:

First, we need to create a `route.go` file for configuring the API routes and add the snippet below:

```go
package api

import "github.com/gin-gonic/gin"

type Config struct {
    Router *gin.Engine
}

func (app *Config) Routes() {
    //routes will come here
}
```

The snippet above does the following:

- Imports the required dependency
- Creates a `Config` struct with a `Router` property to configure the application methods
- Creates a `Routes` function that takes in the `Config` struct as a pointer

Secondly, we need to create a `helper.go` file and add the snippet below:

```go
package api

import (
    "net/http"
    "github.com/gin-gonic/gin"
    "github.com/go-playground/validator/v10"
)

type jsonResponse struct {
    Status  int    `json:"status"`
    Message string `json:"message"`
    Data    any    `json:"data"`
}

var validate = validator.New()

func (app *Config) validateBody(c *gin.Context, data any) error {
    //validate the request body
    if err := c.BindJSON(&data); err != nil {
        return err
    }
    //use the validator library to validate required fields
    if err := validate.Struct(&data); err != nil {
        return err
    }
    return nil
}

func (app *Config) writeJSON(c *gin.Context, status int, data any) {
    c.JSON(status, jsonResponse{Status: status, Message: "success", Data: data})
}

func (app *Config) errorJSON(c *gin.Context, err error, status ...int) {
    statusCode := http.StatusBadRequest
    if len(status) > 0 {
        statusCode = status[0]
    }
    c.JSON(statusCode, jsonResponse{Status: statusCode, Message: err.Error()})
}
```

The snippet above does the following:

- Imports the required dependencies
- Creates a `jsonResponse` struct and `validate` variable to describe the API response and to validate the API fields
- Creates a `validateBody` function that takes in the `Config` struct as a pointer and returns an `error`. Inside the function, we validate that request `data` in the correct format and also use the validator library to also validate and check for the required fields
- Creates a `writeJSON` function that takes in the `Config` struct as a pointer and uses the `jsonResponse` struct to construct API response when there’s no error
- Creates a `errorJSON` function that takes in the `Config` struct as a pointer and uses the `jsonResponse` struct to construct API response when there’s an error

Thirdly, we need to create a `service.go` file that uses the Serverless Functions to abstract the application logic and add the snippet below:

```go
package api

import (
    "bytes"
    "encoding/json"
    "go-user-service/data"
    "io/ioutil"
    "net/http"
)

func (app *Config) getUserService() (*data.Records, error) {
    url := "<NETLIFY FUNCTION GET URL>"
    records := data.Records{}

    resp, err := http.Get(url)
    if err != nil {
        return nil, err
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    err = json.Unmarshal([]byte(body), &records)
    if err != nil {
        return nil, err
    }

    return &records, nil
}

func (app *Config) createUserService(newUser data.User) (*data.CreateResponse, error) {
    url := "<NETLIFY FUNCTION CREATE URL>"
    response := data.CreateResponse{}
    jsonData := data.User{
        FirstName:   newUser.FirstName,
        LastName:    newUser.LastName,
        PhoneNumber: newUser.PhoneNumber,
    }

    postBody, _ := json.Marshal(jsonData)
    bodyData := bytes.NewBuffer(postBody)

    resp, err := http.Post(url, "application/json", bodyData)
    if err != nil {
        return nil, err
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    err = json.Unmarshal([]byte(body), &response)
    if err != nil {
        return nil, err
    }

    return &response, nil
}
```

The snippet above does the following:

- Imports the required dependencies
- Creates a `getUserService` function that takes in the `Config` struct as a pointer, and returns either the list of users or an error. The functions also get the list of users by making an HTTP request to the `get` Serverless Function URL, reads the response accordingly, and returns the appropriate response
- Creates a `createUserService` function that accepts a `newUser`, takes in the `Config` struct as a pointer, and returns the created user details or an error. The functions also creates a user by making an HTTP request to the `create` Serverless Function URL, reads the response accordingly, and returns the appropriate response

Fourthly, we need to create a `handler.go` file for modifying the incoming request and add the snippet below:

```go
package api

import (
    "context"
    "go-user-service/data"
    "net/http"
    "time"
    "github.com/gin-gonic/gin"
)

const appTimeout = time.Second * 10

func (app *Config) getUser() gin.HandlerFunc {
    return func(ctx *gin.Context) {
        _, cancel := context.WithTimeout(context.Background(), appTimeout)
        defer cancel()

        data, err := app.getUserService()
        if err != nil {
            app.errorJSON(ctx, err)
            return
        }

        app.writeJSON(ctx, http.StatusOK, data)
    }
}

func (app *Config) createUser() gin.HandlerFunc {
    return func(ctx *gin.Context) {
        _, cancel := context.WithTimeout(context.Background(), appTimeout)
        var payload data.User
        defer cancel()

        app.validateBody(ctx, &payload)

        newData := data.User{
            FirstName:   payload.FirstName,
            LastName:    payload.LastName,
            PhoneNumber: payload.PhoneNumber,
        }

        data, err := app.createUserService(newData)
        if err != nil {
            app.errorJSON(ctx, err)
            return
        }

        app.writeJSON(ctx, http.StatusAccepted, data)
    }
}
```

The snippet above does the following:

- Imports the required dependencies
- Creates an `appTimeout` variable to set request timeout
- Creates a `getUser` function that returns a Gin-gonic handler and takes in the `Config` struct as a pointer. Inside the returned handler, we defined the API timeout, used the helper functions and the service created earlier to get the list of users
- Creates a `createUser` function that returns a Gin-gonic handler and takes in the `Config` struct as a pointer. Inside the returned handler, we defined the API timeout, used the helper functions and the service created earlier to verify the request body, create a user, and return the created user details

Finally, we need to update the `routes.go` files with the API route and corresponding handler.

```go
package api

import "github.com/gin-gonic/gin"

type Config struct {
    Router *gin.Engine
}

//modify below
func (app *Config) Routes() {
    app.Router.GET("/users", app.getUser())
    app.Router.POST("/users", app.createUser())
}
```

**Putting it all together**
With our API fully set up, we need to create the application entry point. To do this, we need to navigate to the `cmd` folder and, in this folder, create a `main.go` file and add the snippet below:

```go
package main

import (
    "go-user-service/api"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()

    //initialize config
    app := api.Config{Router: router}

    //routes
    app.Routes()

    router.Run(":8080")
}
```

The snippet above does the following:

- Imports the required dependencies
- Creates a Gin router using the `Default` configuration 
- Initialize the `Config` struct by passing in the `Router`
- Adds the route and run the application on port `:8080`

With that done, we can start a development server using the command below:

```bash
go run cmd/main.go 
```

![get list of users](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667262317525_Screenshot+2022-10-29+at+23.06.15.png)
![create a user](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667262364783_Screenshot+2022-10-29+at+23.11.07.png)


We can also verify the APIs by checking the Xata’s workspace

![updated data](https://paper-attachments.dropboxusercontent.com/s_A1144B74EC1072093F0D2701A540D1E74AD827D7B0FFCD60C26EE8B5BA462734_1667262482438_Screenshot+2022-11-01+at+01.27.28.png)

## Conclusion

This post discussed how to quickly create user management APIs in Go without manually deploying and managing databases and servers. With the powerful trio of Xata, Netlify, and Cloudinary, developers can build and ship applications faster by focusing on what matters and not being bothered by infrastructure bottlenecks.

These resources might be helpful:

- [Xata official docs](https://xata.io/docs/overview?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)
- [Netlify Serverless Functions](https://www.netlify.com/products/functions/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)
- [Cloudinary official docs](https://cloudinary.com/documentation?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)
- [Go HTTP Library](https://pkg.go.dev/net/http)