Skip to content

Game of thrones API built in Golang for an interview challenge. Uses ElasticSearch and RabbitMQ for an event driven data syncronization, Docker compose to deploy services and PostgreSQL as database.

Notifications You must be signed in to change notification settings

albegonzalezp/go-got-api

Repository files navigation

Go Game of Thrones API

A RESTful API for managing Game of Thrones characters and actors, built with Go.

Features

  • RESTful API endpoints for characters and actors
  • Elasticsearch integration for full-text search
  • RabbitMQ for event-driven architecture
  • PostgreSQL for data persistence
  • Comprehensive test coverage with detailed reports
  • Docker support for easy deployment

Prerequisites

  • Go 1.21 or later
  • Docker and Docker Compose
  • Make (for initialization and testing)

Getting Started

  1. If downloaded the .zip file, just unzip it.

  2. Clone the repository:

git clone https://github.com/albegonzalezp/go-got-api.git
cd go-got-api
  1. Initialize the project (this will set up all required services):
make all
  1. Run tests:
make test        # Run all tests with coverage

API Usage

Complete Example Flow

Here's the complete flow for creating and linking a character with an actor:

  1. First, create the character:
curl -X POST http://localhost:8080/api/v1/characters \
    -H "Content-Type: application/json" \
    -d '{
      "characterName": "Jon Snow",
      "characterLink": "https://example.com/jon-snow",
      "houseName": ["Stark", "Targaryen"],
      "royal": true
    }'
  1. Then, create the actor:
curl -X POST http://localhost:8080/api/v1/actors \
    -H "Content-Type: application/json" \
    -d '{
      "actorName": "Kit Harington",
      "actorLink": "https://example.com/kit-harington",
      "seasonsActive": [1,2,3,4,5,6,7,8]
    }'
  1. Link the actor to the character:
curl -X POST http://localhost:8080/api/v1/relations/characters/1/actors/1
  1. Verify the relationship:
# Get all actors for the character
curl -X GET http://localhost:8080/api/v1/relations/characters/1/actors

# Search characters by actor name, will return all the characters that have a actor associated
curl -X GET "http://localhost:8080/api/v1/characters/search?q=actor:Kit%20Harington"

# Search actors by character name, will return all the actors that have a character associated
curl -X GET "http://localhost:8080/api/v1/actors/search?q=character:Jon%20Snow"

Characters

Create a Character

curl -X POST http://localhost:8080/api/v1/characters \
    -H "Content-Type: application/json" \
    -d '{
      "characterName": "Jon Snow",
      "characterLink": "https://example.com/jon-snow",
      "houseName": ["Stark", "Targaryen"],
      "royal": true
    }'

Get a Character

curl -X GET http://localhost:8080/api/v1/characters/1

Update a Character

curl -X PUT http://localhost:8080/api/v1/characters/1 \
    -H "Content-Type: application/json" \
    -d '{
      "characterName": "Jon Snow",
      "characterLink": "https://example.com/jon-snow-changed",
      "houseName": ["Stark", "Targaryen", "CoolHouse"],
      "royal": true
    }'

Delete a Character

curl -X DELETE http://localhost:8080/api/v1/characters/1

Search Characters

# Search by character name
curl -X GET "http://localhost:8080/api/v1/characters/search?q=Jon%20Snow"

# Search by actor name
curl -X GET "http://localhost:8080/api/v1/characters/search?q=actor:Kit%20Harington"

Actors

Create an Actor

curl -X POST http://localhost:8080/api/v1/actors \
    -H "Content-Type: application/json" \
    -d '{
      "actorName": "Kit Harington",
      "actorLink": "https://example.com/kit-harington"
    }'

Get an Actor

curl -X GET http://localhost:8080/api/v1/actors/1

Update an Actor

curl -X PUT http://localhost:8080/api/v1/actors/1 \
    -H "Content-Type: application/json" \
    -d '{
      "actorName": "Kit Harington",
      "actorLink": "https://example.com/kit-harington"
    }'

Delete an Actor

curl -X DELETE http://localhost:8080/api/v1/actors/1

Character-Actor Relations

Add an Actor to a Character

curl -X POST http://localhost:8080/api/v1/relations/characters/1/actors/1

Remove an Actor from a Character

curl -X DELETE http://localhost:8080/api/v1/relations/characters/1/actors/1

Get All Actors for a Character

curl -X GET http://localhost:8080/api/v1/relations/characters/1/actors

Get All Characters for an Actor

curl -X GET http://localhost:8080/api/v1/relations/actors/1/characters

Development

Running in Development Mode

make dev

View Available Commands

make help

Cleanup

make clean  # Stop and remove all services

RabbitMQ Contracts

The API uses RabbitMQ for event-driven communication between services. Below are the contracts for message publishing and consumption.

Exchange and Queue Configuration

  • Exchange Name: data_sync
  • Exchange Type: topic
  • Queue Name: elasticsearch_sync

Message Format

All messages follow this JSON structure:

{
  "action": "event.action",
  "data": {
    // Event-specific data
  }
}

Published Events

Character Events

  1. Character Created

    {
      "action": "character.created",
      "data": {
        "id": 1,
        "name": "Jon Snow",
        "houseName": ["Stark", "Targaryen"],
        "royal": true
         // Add more fields to be added dynamically,
      }
    }
  2. Character Updated

    {
      "action": "character.updated",
      "data": {
        "id": 1,
        "name": "Jon Snow",
        "houseName": ["Stark", "Targaryen", "CoolHouse"],
        "royal": true
         // Add more fields to be added dynamically,
      }
    }
  3. Character Deleted

    {
      "action": "character.deleted",
      "data": {
        "id": 1
      }
    }

Actor Events

  1. Actor Created

    {
      "action": "actor.created",
      "data": {
        "id": 1,
        "name": "Kit Harington",
        "seasonsActive": [1,2,3,4,5,6,7,8]
        // Add more fields to be added dynamically,
      }
    }
  2. Actor Updated

    {
      "action": "actor.updated",
      "data": {
        "id": 1,
        "name": "Kit Harington",
        "seasonsActive": [1,2,3,4,5,6,7,8]
         // Add more fields to be added dynamically,
      }
    }
  3. Actor Deleted

    {
      "action": "actor.deleted",
      "data": {
        "id": 1
      }
    }

Relation Events

  1. Actor Added to Character

    {
      "action": "relation.actor.added",
      "data": {
        "characterId": 1,
        "actorId": 1
      }
    }
  2. Actor Removed from Character

    {
      "action": "relation.actor.removed",
      "data": {
        "characterId": 1,
        "actorId": 1
      }
    }

Consumer Contracts

The sync service consumes messages from the elasticsearch_sync queue and updates Elasticsearch accordingly. It handles the following actions:

  1. Character Events

    • character.created: Index new character in Elasticsearch
    • character.updated: Update character in Elasticsearch
    • character.deleted: Remove character from Elasticsearch
  2. Actor Events

    • actor.created: Index new actor in Elasticsearch
    • actor.updated: Update actor in Elasticsearch
    • actor.deleted: Remove actor from Elasticsearch
  3. Relation Events

    • relation.actor.added: Update character and actor documents in Elasticsearch
    • relation.actor.removed: Update character and actor documents in Elasticsearch

Error Handling

  • Invalid messages are logged and rejected
  • Failed operations are retried up to 3 times
  • After retries, failed messages are moved to a dead letter queue
  • All errors are logged with appropriate context

Elasticsearch Configuration

The API uses Elasticsearch for full-text search capabilities. The current setup is optimized for development:

Development Setup

  • Security: Disabled for development convenience (xpack.security.enabled=false)
  • Memory: Limited to 512MB (-Xms512m -Xmx512m)
  • Mode: Single-node cluster (discovery.type=single-node)
  • Port: Accessible on http://localhost:9200

Security Note

⚠️ Important: The current development setup has security features disabled. In a production environment, you should:

  1. Enable security:

    environment:
      - xpack.security.enabled=true
  2. Set up authentication:

    • Configure proper API keys
    • Use username/password authentication
    • Enable TLS/SSL for encrypted communication
  3. Configure proper access control:

    • Set up role-based access control (RBAC)
    • Define proper index permissions
    • Use secure network settings

Indices

The API creates two main indices:

  1. Characters Index (characters)

    • Fields: name, houseName, royal, related_actors
    • Text analysis: standard analyzer
    • Nested fields for actor relationships
  2. Actors Index (actors)

    • Fields: name, seasonsActive, related_characters
    • Text analysis: standard analyzer
    • Nested fields for character relationships

Test Environment

For testing, separate indices are used:

  • test_characters
  • test_actors

These are automatically created when running tests to avoid interference with production data.

API Routes

Characters

Method Route Description Request Body Response
POST /api/v1/characters Create a new character { "characterName": string, "characterLink": string, "houseName": string[], "royal": boolean } Created character
GET /api/v1/characters/{id} Get a character by ID - Character details
PUT /api/v1/characters/{id} Update a character { "characterName": string, "characterLink": string, "houseName": string[], "royal": boolean } Updated character
DELETE /api/v1/characters/{id} Delete a character - -
GET /api/v1/characters/search Search characters Query params: q=search_term List of matching characters

Actors

Method Route Description Request Body Response
POST /api/v1/actors Create a new actor { "actorName": string, "actorLink": string, "seasonsActive": number[] } Created actor
GET /api/v1/actors/{id} Get an actor by ID - Actor details
PUT /api/v1/actors/{id} Update an actor { "actorName": string, "actorLink": string, "seasonsActive": number[] } Updated actor
DELETE /api/v1/actors/{id} Delete an actor - -
GET /api/v1/actors/search Search actors Query params: q=search_term List of matching actors

Relations

Method Route Description Request Body Response
POST /api/v1/relations/characters/{characterId}/actors/{actorId} Link an actor to a character - -
DELETE /api/v1/relations/characters/{characterId}/actors/{actorId} Remove an actor from a character - -
GET /api/v1/relations/characters/{characterId}/actors Get all actors for a character - List of actors
GET /api/v1/relations/actors/{actorId}/characters Get all characters for an actor - List of characters

Search Capabilities

The search endpoints (/characters/search and /actors/search) support the following query formats:

  1. Simple Text Search

    GET /api/v1/characters/search?q=Jon%20Snow
    

    Searches for characters with "Jon Snow" in their name.

  2. Actor-based Search

    GET /api/v1/characters/search?q=actor:Kit%20Harington
    

    Finds all characters played by Kit Harington.

  3. Character-based Search

    GET /api/v1/actors/search?q=character:Jon%20Snow
    

    Finds all actors who played Jon Snow.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Game of thrones API built in Golang for an interview challenge. Uses ElasticSearch and RabbitMQ for an event driven data syncronization, Docker compose to deploy services and PostgreSQL as database.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages