Skip to content

mr-polymath/platform-go-challenge

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GlobalWebIndex Engineering Challenge

Favourites API

A small Go web service that demonstrates a favourites API:

  • list a user's favourites
  • add/remove an asset
  • update an asset's description.

The project uses a concurrency-safe in-memory store and a simple JWT-based auth middleware for protected routes.

This README provides a concise developer guide:

  • How to build, run and test locally
  • API endpoints and example curl commands
  • Notes on the in-memory store and where to add persistence

Build

From the repository root:

go build ./...

Run (dev)

Start the server (binds to :3002):

go run ./cmd/app

The server seeds an in-memory store on startup and prints two seeded user UUIDs you can use in examples.

Tests

Run the unit tests:

go test ./...

Current tests cover the handler layer and in-memory store.

Docker

A Dockerfile is provided that builds the Go binary inside a golang builder image and produces a runnable image that exposes port 3002. The current Dockerfile uses a single-stage build based on the official golang image and outputs a static binary named favourites-app.

Build the image:

docker build -t platform-go-challenge:latest .

Run the container (maps local 3002 to container 3002):

docker run --rm -p 3002:3002 platform-go-challenge:latest

API

All protected endpoints require a Bearer JWT token. Use the token generation endpoint to get a token for a given user UUID. Note: the auth middleware requires the token's user (subject) to match the {userId} path parameter — otherwise requests will be rejected with 403 Forbidden.

  1. Generate token
  • POST /token
  • Body: { "user_id": "" }
  • Response: { "token": "" }

Example:

curl -s -X POST -H "Content-Type: application/json" \
	-d '{"user_id":"431ff79b-4e65-4625-9f7f-c8125e2be057"}' \
	http://localhost:3002/token

Use the returned token in the Authorization: Bearer <token> header for subsequent requests. The token subject must equal the {userId} path parameter on protected routes.

  1. Add favourite
  • POST /users/{userId}/favourites
  • Header: Authorization: Bearer
  • Body: JSON representation of model.Asset. For convenience the tests and seed helpers use model.NewAsset(...) shapes. Minimal example:
{
  "type": "insight",
  "description": "Top insight",
  "data": { "text": "40% of..." }
}

Example:

curl -X POST -H "Content-Type: application/json" \
	-H "Authorization: Bearer <token>" \
	-d '{"type":"insight","description":"Test desc","data":{"text":"hello"}}' \
	http://localhost:3002/users/<user-uuid>/favourites

Successful response: 201 Created with JSON { "message": "favourite added", "favourite": { ... } }

  1. List favourites
  • GET /users/{userId}/favourites
  • Header: Authorization: Bearer
  • Query params (optional): offset, limit, sortBy (description|type), order (asc|desc)

Example:

curl -H "Authorization: Bearer <token>" \
	http://localhost:3002/users/<user-uuid>/favourites

Response: 200 OK { "favourites": [ ... ] }

  1. Patch description
  • PATCH /users/{userId}/favourites/{assetId}
  • Header: Authorization: Bearer
  • Body: { "description": "New description" }
  • Response: 204 No Content on success (current implementation sends a JSON message with the 204 status)
  1. Delete favourite
  • DELETE /users/{userId}/favourites/{assetId}
  • Header: Authorization: Bearer
  • Response: 200 OK { "message": "favourite removed", "favouriteId": "" }

Seeded users

The seed helper pre-populates two demo users. When you run the server you should see printed UUIDs similar to:

  • 431ff79b-4e65-4625-9f7f-c8125e2be057
  • d61733f6-910e-4e26-bb31-0cac3a7d4279

Use these UUIDs to generate tokens and try the endpoints.

Extending persistence

The storage abstraction is defined by internal/db.FavouriteRepository. To add persistence (Postgres, Redis, etc.) implement that interface and replace the db.NewMemoryStore() call in cmd/app/main.go with your implementation.

Key methods to implement:

  • GetAllFavourites(userID uuid.UUID, q PageQuery) ([]model.Asset, error)
  • AddFavourite(userID uuid.UUID, a model.Asset) error
  • RemoveFavourite(userID uuid.UUID, assetID uuid.UUID) error
  • PatchFavourite(userID uuid.UUID, assetID uuid.UUID, description string) error

Notes and caveats

  • The store is in-memory and ephemeral. Restarting the server clears all runtime state.
  • The JWT secret is hard-coded for the challenge and should be replaced by a secure secret management strategy for any real deployment.
  • The model.Asset.Data field uses any to keep the example compact. For a production service a well-defined schema per asset type with validation is recommended.

Generating Swagger docs

The project uses swaggo/swag to generate Swagger documentation. To regenerate the docs run the following command from the repository root:

$(go env GOPATH)/bin/swag init -g main.go -d cmd/app,internal/api,internal/model --parseInternal -o internal/swagger

Notes:

  • The command writes generated files into the internal/swagger directory (adjust -o if you prefer a different output location).
  • Running swag init will overwrite the generated files; if you manually customize internal/swagger you may want to keep a backup or script changes post-generation.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Go 99.0%
  • Dockerfile 1.0%