Building a Bingo game backend with encore.dev
Tags: go, backend, framework
Published: 2021-05-05 02:55:06

---
title: Building a Bingo game backend with encore.dev
published: true
description: Testing Encore.dev Go framework
tags: go, backend, framework
//cover_image: https://direct_url_to_image.jpg
---
You can check the original post in my [blog](https://eaglewas.me/blog/en/bingo-backend-encore)

First of all, let's talk about [encore.dev](https://encore.dev) which is a magical Go backend framework with almost 0 boilerplate,tracing out of the box, serverless deploys immediately, support for postgreSQL, auth and much more! I first heard about this framework in the [TLDR Newsletter](https://tldr.tech/) and I tried it for a little bit and I'm falling in love with it even though I barely know how to code in Go!

To start a new project you need to download and install encore, the good thing is that is available in brew for mac so we can just do the following command in our terminal:
```bash 
$ brew install encoredev/tap/encore
//then run 
$ encore app create
```
When doing the ```encore app create``` it will ask you to login in our encore app to create a new project, after doing that it will ask you for the name of the app and a starter template, for this project I chose the Hello World template just to have a base to start with, after finishing with the prompt questions you'll have something like this
![encore app create](https://i.imgur.com/uuE7yA2.png)

Now if we go into that folder with ```cd bingo``` and then do ```encore run``` we should be able to go to ```http://localhost:64675/${project-id}``` and see the "API Explorer" which is a nice interface that lists all our API endpoints so we can trigger the request from there with a custom body, params and all that
![encore api explorer](https://i.imgur.com/bSQuZfR.png)
There's also a nice thing about this app that encore creates for us, we also have available an auto generated API docs which specify a little description about the API endpoint, the params types and response schema of each defined endpoint

## Creating our bingo database and migration

In this post I won't be generating all the authentication part of the app, since it's a small project, I will be creating the following routes with it's functionality:
- User creation route (with a number list)
- Randomizer route (to get a random number and compare to the number list of a specified user)

### Doing the migration
So let's start with how the migration of the user is going to look, to create the right file, we need to add a new folder called ```bingo``` on the root of the project, then create a ```migration``` folder with a file on it called ```1_create_user_table.up.sql```, 
__Notes:__
- the number of the file means the order that the migrations are going to be executed
- after the first underscore (_) comes the name of the migration
- we have to add the extension ```.up.sql``` to all migrations

```sql
CREATE TABLE client (
  email TEXT PRIMARY KEY,
  list INTEGER []
);
```

## Defining the logic of the route
after doing this, whenever we do encore run the next time it will run our migration, but before that let's create a ```bingo.go``` file inside the bingo folder to create our routes inside of it.

first we need to include the package name which should match the folder name (our bingo service) then after that we should define our imports and include encore sqldb handler inside of it
```go
package bingo

import (
	"context"

	"encore.dev/storage/sqldb"
)
```

now we need to declare some structs for our response and request for the route to be used inside the function to cover our needs, we need a struct for the request params and a struct for the response we're sending, that should look like the following

```go
type UserParams struct {
	Email string
}

type RegisterResponse struct {
	Email string
	List  []int
}
```
then it comes the fun part, creating the function that in charge of creating the list, the user, store it in the database and returnn it, NOTE: keep in mind that we need to add the comment ```//encore:api public``` before the function so encore can detect it as an API route, the following code looks something like this:

```go
//encore:api public
func RegisterUser(ctx context.Context, params *UserParams) (*RegisterResponse, error) {
	var list = generateList(0, 100)
	var user RegisterResponse
	err := sqldb.QueryRow(ctx, `
    INSERT INTO "client" (email, list)
    VALUES ($1, $2)
	RETURNING *;
  `, params.Email, list).Scan(&user.Email, &user.List)
	if err != nil {
		return nil, err
	}
	return &user, nil
}

func generateList(min, max int) []int {
	a := make([]int, max-min+1)
	for i := range a {
		a[i] = min + i
	}
	return a
}
```

## Verifying the database

Now after doing that we can do ```encore run``` go to localhost:4060 and try hitting the registerUser Endpoint with the request to call the API

**quick note:** To check the database data, you can do ```encore db conn-uri ${service name}``` in this case service name is bingo so it should be ```encore db conn-uri bingo```, then you can take this URL and use it in postico or some other postgreSQL UI app to see the table and the rows, also you can use the PSQL command in mac (you need to install it first with brew)

## Selecting a number and updating the array

Now the next task is to get the list array from a user, then select a random number from the list, remove that number from that list, updating it in the database and return the selected number! so let's get started, we will do this code in the same bingo.go file:

```go
//encore:api public
func DrawFromList(ctx context.Context, params *UserParams) (*DrawResponse, error) {
	var list []int // empty list to be asssigned after the SQL query
	err := sqldb.QueryRow(ctx, `
	SELECT list from "client"
	WHERE email = ($1)`, params.Email).Scan(&list)
	if err != nil {
		return nil, err
	}
  var response DrawResponse
  // generate a random number everytime you hit the request 
	rand.Seed(time.Now().UnixNano())
	var randomIndex = rand.Intn(len(list) - list[0] + 1 + list[0])
  // assign the random number to the response selected struct
	response.Selected = list[randomIndex]
  //remove the item from the array by the index
	list = RemoveIndex(list, randomIndex)
  // update the list of the user with the new one without the selected item
	sqldb.QueryRow(ctx, `
	UPDATE "client"
	SET list = ($1)
	WHERE email = ($2)`, list, params.Email)
	response.Removed = true
	return &response, nil
}

//Function to remove an item from an array by the index
func RemoveIndex(s []int, index int) []int {
	return append(s[:index], s[index+1:]...)
}
```

After this we can commit what we did, and then run ```git push encore``` to build the project and deploy it inside encore.dev platform (which uses a free tier of aws under the hood) and if we go to [encore.dev](https://encore.dev) and select the project you should see a build completed
![git push encore](https://i.imgur.com/zkPeLoU.png)
![build completed](https://i.imgur.com/wMWrpnc.png)

Also, to check the database in production, we can use ```encore db shell bingo --env=prod``` and from here we will be able to see our database with psql from the terminal

So TLDR:

In this tuto we created a encore.dev backend app from scratch which uses two routes to create a user based on an email and assigns a list of a 100 numbers to it, and another route to draw a random number and remove it from that user array list

you can test this API on this url https://bingo-c7m2.encoreapi.com/prod/bingo.RegisterUser with this CURL to register:
```bash
curl --location --request POST 'https://bingo-c7m2.encoreapi.com/prod/bingo.RegisterUser' \
--header 'Content-Type: application/json' \
--data-raw '{
    "Email": "your-mail@gg.com"
}'
```

and this CURL to draw a number
```bash
curl --location --request POST 'https://bingo-c7m2.encoreapi.com/prod/bingo.DrawFromList' \
--header 'Content-Type: application/json' \
--data-raw '{
    "Email": "your-mail@gg.com"
}'
```

Sources
- https://encore.dev
- https://www.postgresqltutorial.com/postgresql-array/
- https://www.digitalocean.com/community/tutorials/defining-structs-in-go-es
- Encore.dev slack group
- https://www.golangprograms.com/how-to-delete-an-element-from-a-slice-in-golang.html
- https://www.postgresqltutorial.com/postgresql-update/