DEV Community

Vaidehi Adhi
Vaidehi Adhi

Posted on

Building a Meme Battle Royale with SurrealDB and Gofr

In this article, I'll walk you through creating a fun and engaging Meme Battle Royale system using SurrealDB and the Gofr framework. This project demonstrates how to integrate SurrealDB, a powerful multi-model database, with Gofr, an open-source Go web framework, to build a system where users can vote on their favorite memes in head-to-head battles.

What is SurrealDB?

SurrealDB is a scalable, distributed database that combines the flexibility of document databases with the power of graph databases and the reliability of traditional relational databases. It's designed for modern applications that require complex data relationships while maintaining high performance and ease of use.

Project Overview

The Meme Battle Royale is a voting system that allows users to:

  • Upload memes with titles and URLs
  • Participate in head-to-head battles between two random memes
  • Vote for their favorite memes
  • View a leaderboard of the most popular memes

The system tracks wins and losses for each meme, creating an engaging competition platform.

Setting Up SurrealDB with Docker

Getting started with SurrealDB is straightforward using Docker:

  1. First, install Docker if you haven't already.
  2. Pull and run the SurrealDB container:

docker run --name surrealdb -p 8000:8000 surrealdb/surrealdb:latest start --log debug

Database Schema

Our system uses two main tables: memes and votes. Here's how we define them in SurrealDB:

DEFINE TABLE memes SCHEMALESS;
DEFINE FIELD title ON TABLE memes TYPE string;
DEFINE FIELD url ON TABLE memes TYPE string;
DEFINE FIELD wins ON TABLE memes TYPE int DEFAULT 0;
DEFINE FIELD losses ON TABLE memes TYPE int DEFAULT 0;

DEFINE TABLE votes SCHEMALESS;
DEFINE FIELD meme1_id ON TABLE votes TYPE string;
DEFINE FIELD meme2_id ON TABLE votes TYPE string;
DEFINE FIELD winner_id ON TABLE votes TYPE string;
Enter fullscreen mode Exit fullscreen mode

Integrating SurrealDB with Gofr

The integration between SurrealDB and Gofr is handled through a configuration setup:

client := surrealdb.New(&surrealdb.Config{
    Host:       "localhost",
    Port:       9000,
    Username:   "root",
    Password:   "root",
    Namespace:  "app",
    Database:   "meme_battle",
    TLSEnabled: false,
})
Enter fullscreen mode Exit fullscreen mode

Core Data Models

Our application uses two main data structures:

type Meme struct {
    ID     string `json:"id,omitempty"`
    Title  string `json:"title"`
    URL    string `json:"url"`
    Wins   int    `json:"wins"`
    Losses int    `json:"losses"`
}

type Vote struct {
    Meme1ID  string `json:"meme1_id"`
    Meme2ID  string `json:"meme2_id"`
    WinnerID string `json:"winner_id"`
}
Enter fullscreen mode Exit fullscreen mode

API Endpoints

1. Create Meme (POST /memes)

This endpoint allows users to add new memes to the battle system:

POST http://localhost:9000/memes
Content-Type: application/json

{
    "title": "Monday Motivation",
    "url": "https://example.com/meme1.jpg",
    "wins": 0,
    "losses": 0
}
Enter fullscreen mode Exit fullscreen mode

2. Get All Memes (GET /memes)

Retrieves all memes in the system:

GET http://localhost:9000/memes
Enter fullscreen mode Exit fullscreen mode

3. Submit Vote (POST /vote)

Records a vote in a head-to-head battle:

POST http://localhost:9000/vote
Content-Type: application/json

{
    "meme1_id": "memes:75ut1jzxj04agbv944yi",
    "meme2_id": "memes:cgbrmfm7x66g56nhxkgg",
    "winner_id": "memes:75ut1jzxj04agbv944yi"
}
Enter fullscreen mode Exit fullscreen mode

4. View Leaderboard (GET /leaderboard)

Shows the top-performing memes:

GET http://localhost:9000/leaderboard
Enter fullscreen mode Exit fullscreen mode

Implementation Details

The core of our implementation lies in the main.go file, where we set up our routes and handlers:

func main() {
    app := gofr.New()

    // Set up SurrealDB client
    client := surrealdb.New(&surrealdb.Config{...})
    app.AddSurrealDB(client)

    // Register routes
    app.POST("/memes", addMeme)
    app.GET("/memes", getMemes)
    app.POST("/vote", voteMeme)
    app.GET("/leaderboard", getLeaderboard)

    app.Run()
}
Enter fullscreen mode Exit fullscreen mode

Each endpoint handler is implemented with proper error handling and database operations. For example, here's how we handle adding a new meme:

func addMeme(ctx *gofr.Context) (interface{}, error) {
    var meme Meme
    if err := ctx.Bind(&meme); err != nil {
        return ErrorResponse{Message: "Invalid request body"}, nil
    }

    result, err := ctx.SurrealDB.Create(ctx, "memes", map[string]interface{}{
        "title":  meme.Title,
        "url":    meme.URL,
        "wins":   meme.Wins,
        "losses": meme.Losses,
    })
    if err != nil {
        return nil, err
    }

    return result, nil
}
Enter fullscreen mode Exit fullscreen mode

Testing the System

Using Postman or curl, you can test each endpoint. For example, to add a new meme:

curl -X POST http://localhost:9000/memes \
     -H "Content-Type: application/json" \
     -d '{"title":"Work From Home","url":"https://example.com/wfh.jpg"}'
Enter fullscreen mode Exit fullscreen mode

Conclusion

This project demonstrates the power and flexibility of using SurrealDB with the Gofr framework. The combination provides a solid foundation for building scalable, real-time voting systems. The schema-less nature of SurrealDB makes it easy to evolve the data model as requirements change, while Gofr's simplicity allows for rapid development of REST APIs.
Whether you're building a meme battle system or any other type of voting application, this stack provides the tools needed for success. The complete code for this project is available on GitHub, and I encourage you to explore, fork, and contribute to its development.

If you found this article helpful, please consider starring the Gofr repository and contributing to the community!


⭐ Star https://github.com/gofr-dev/gofr on GitHub

Top comments (0)