DEV Community

Dany the spacecowboy
Dany the spacecowboy

Posted on

Building a Bingo game backend with encore.dev

You can check the original post in my blog

First of all, let's talk about 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 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:

$ brew install encoredev/tap/encore
//then run 
$ encore app create
Enter fullscreen mode Exit fullscreen mode

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

Now if we go into that folder with

cd bingo

and then do

encore run

we should be able to go to


 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 []
);
Enter fullscreen mode Exit fullscreen mode

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


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

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

type UserParams struct {
    Email string
}

type RegisterResponse struct {
    Email string
    List  []int
}
Enter fullscreen mode Exit fullscreen mode

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:

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

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:

//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:]...)
}
Enter fullscreen mode Exit fullscreen mode

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 and select the project you should see a build completed
git push encore
build completed

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:

curl --location --request POST 'https://bingo-c7m2.encoreapi.com/prod/bingo.RegisterUser' \
--header 'Content-Type: application/json' \
--data-raw '{
    "Email": "your-mail@gg.com"
}'
Enter fullscreen mode Exit fullscreen mode

and this CURL to draw a number

curl --location --request POST 'https://bingo-c7m2.encoreapi.com/prod/bingo.DrawFromList' \
--header 'Content-Type: application/json' \
--data-raw '{
    "Email": "your-mail@gg.com"
}'
Enter fullscreen mode Exit fullscreen mode

Sources

Top comments (0)