A RESTful API for managing Game of Thrones characters and actors, built with Go.
- 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
- Go 1.21 or later
- Docker and Docker Compose
- Make (for initialization and testing)
-
If downloaded the .zip file, just unzip it.
-
Clone the repository:
git clone https://github.com/albegonzalezp/go-got-api.git
cd go-got-api- Initialize the project (this will set up all required services):
make all- Run tests:
make test # Run all tests with coverageHere's the complete flow for creating and linking a character with an actor:
- 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
}'- 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]
}'- Link the actor to the character:
curl -X POST http://localhost:8080/api/v1/relations/characters/1/actors/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"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
}'curl -X GET http://localhost:8080/api/v1/characters/1curl -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
}'curl -X DELETE http://localhost:8080/api/v1/characters/1# 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"curl -X POST http://localhost:8080/api/v1/actors \
-H "Content-Type: application/json" \
-d '{
"actorName": "Kit Harington",
"actorLink": "https://example.com/kit-harington"
}'curl -X GET http://localhost:8080/api/v1/actors/1curl -X PUT http://localhost:8080/api/v1/actors/1 \
-H "Content-Type: application/json" \
-d '{
"actorName": "Kit Harington",
"actorLink": "https://example.com/kit-harington"
}'curl -X DELETE http://localhost:8080/api/v1/actors/1curl -X POST http://localhost:8080/api/v1/relations/characters/1/actors/1curl -X DELETE http://localhost:8080/api/v1/relations/characters/1/actors/1curl -X GET http://localhost:8080/api/v1/relations/characters/1/actorscurl -X GET http://localhost:8080/api/v1/relations/actors/1/charactersmake devmake helpmake clean # Stop and remove all servicesThe API uses RabbitMQ for event-driven communication between services. Below are the contracts for message publishing and consumption.
- Exchange Name:
data_sync - Exchange Type:
topic - Queue Name:
elasticsearch_sync
All messages follow this JSON structure:
{
"action": "event.action",
"data": {
// Event-specific data
}
}-
Character Created
{ "action": "character.created", "data": { "id": 1, "name": "Jon Snow", "houseName": ["Stark", "Targaryen"], "royal": true // Add more fields to be added dynamically, } } -
Character Updated
{ "action": "character.updated", "data": { "id": 1, "name": "Jon Snow", "houseName": ["Stark", "Targaryen", "CoolHouse"], "royal": true // Add more fields to be added dynamically, } } -
Character Deleted
{ "action": "character.deleted", "data": { "id": 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, } } -
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, } } -
Actor Deleted
{ "action": "actor.deleted", "data": { "id": 1 } }
-
Actor Added to Character
{ "action": "relation.actor.added", "data": { "characterId": 1, "actorId": 1 } } -
Actor Removed from Character
{ "action": "relation.actor.removed", "data": { "characterId": 1, "actorId": 1 } }
The sync service consumes messages from the elasticsearch_sync queue and updates Elasticsearch accordingly. It handles the following actions:
-
Character Events
character.created: Index new character in Elasticsearchcharacter.updated: Update character in Elasticsearchcharacter.deleted: Remove character from Elasticsearch
-
Actor Events
actor.created: Index new actor in Elasticsearchactor.updated: Update actor in Elasticsearchactor.deleted: Remove actor from Elasticsearch
-
Relation Events
relation.actor.added: Update character and actor documents in Elasticsearchrelation.actor.removed: Update character and actor documents in Elasticsearch
- 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
The API uses Elasticsearch for full-text search capabilities. The current setup is optimized for development:
- 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
-
Enable security:
environment: - xpack.security.enabled=true
-
Set up authentication:
- Configure proper API keys
- Use username/password authentication
- Enable TLS/SSL for encrypted communication
-
Configure proper access control:
- Set up role-based access control (RBAC)
- Define proper index permissions
- Use secure network settings
The API creates two main indices:
-
Characters Index (
characters)- Fields: name, houseName, royal, related_actors
- Text analysis: standard analyzer
- Nested fields for actor relationships
-
Actors Index (
actors)- Fields: name, seasonsActive, related_characters
- Text analysis: standard analyzer
- Nested fields for character relationships
For testing, separate indices are used:
test_characterstest_actors
These are automatically created when running tests to avoid interference with production data.
| 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 |
| 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 |
| 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 |
The search endpoints (/characters/search and /actors/search) support the following query formats:
-
Simple Text Search
GET /api/v1/characters/search?q=Jon%20SnowSearches for characters with "Jon Snow" in their name.
-
Actor-based Search
GET /api/v1/characters/search?q=actor:Kit%20HaringtonFinds all characters played by Kit Harington.
-
Character-based Search
GET /api/v1/actors/search?q=character:Jon%20SnowFinds all actors who played Jon Snow.
This project is licensed under the MIT License - see the LICENSE file for details.