This repo contains a GraphQL API for a simplified version of minesweeper. It exposes a Game
type and a Square
type, as well as mutations to create a game and select a square. The GraphQL playground is enabled and can be explored at https://minesweeper.kraw.cz/graphql
Prerequisites
- Yarn v1.13+
- Node v12+
- Docker v19+, if building images locally
- Terraform v0.12+, if deploying infrastructure locally
Application Setup
- Run
yarn
to install dependencies and copy.env.example
into.env
- Populate
.env
with proper values for the DB. This file is only for simplified local development; In production, CI pulls the values from AWS Secrets Manager - Run
yarn start
to start a local express server on port 8080.
Infrastructure Setup
- Enter the
terraform
directory - Run
terraform init
to initialize terraform - Run
terraform plan
to review infrastructure changes - Run
terraform apply
to deploy those changes
The GraphQL endpoints can be queried at https://minesweeper.kraw.cz/graphql. The playground contains tabs for types in the Schema, as well as available Queries and Mutations.
Example queries and mutations have been provided here for simplicity, but most properties can be omitted from the response.
The createGame
mutation accepts two arguments, width
and height
, with integer values between 2
and 50
and returns a Game
object.
Request
mutation {
createGame(width: 5, height: 5) {
id
createdAt
modifiedAt
completedAt
height
width
result
board {
id
gameId
selected
hasBomb
x
y
adjacentBombs
}
}
}
Response
{
"data": {
"createGame": {
"id": "151c381b-3234-4610-9826-745d3f5afcf0",
"createdAt": "2019-10-27T00:20:12.480Z",
"modifiedAt": "2019-10-27T00:20:12.480Z",
"completedAt": null,
"height": 5,
"width": 5,
"result": null,
"board": [
[
{
"id": "56eaee12-6bed-4f5f-8cab-85be1e71e330",
"gameId": "151c381b-3234-4610-9826-745d3f5afcf0",
"selected": false,
"hasBomb": false,
"x": 0,
"y": 0,
"adjacentBombs": 0
},
...
]
]
}
}
}
The move
mutation accepts three arguments, a uuid gameId
, and integer values x
and y
and returns a Game
object.
If the user selects a bomb or the last non-bomb square, the game will end and contain a result
and a completedAt
attribute.
Request
mutation {
move(gameId: "151c381b-3234-4610-9826-745d3f5afcf0", x: 2, y: 3) {
modifiedAt
completedAt
result
board {
hasBomb
selected
adjacentBombs
}
}
}
Response
{
"data": {
"move": {
"modifiedAt": "2019-10-27T00:20:12.480Z",
"completedAt": null,
"result": null,
"board": [
[
{
"hasBomb": false,
"selected": false,
"adjacentBombs": 0
},
{
"hasBomb": false,
"selected": false,
"adjacentBombs": 0
},
...
]
]
}
}
}
There are no arguments for the games query. This example is only requesting a few properties, although any properties of the Game
schema can be requested.
Request
query {
games {
id
width
height
createdAt
result
}
}
Response
{
"data": {
"games": [
{
"id": "334cfdb9-a1c3-45df-bbc1-754de27e78eb",
"width": 5,
"height": 5,
"createdAt": "2019-10-26T23:02:20.801Z",
"result": "WON"
},
...
]
}
}
The application server entrypoint is in main.js
(index.js
just contains esm). It uses Apollo for the GraphQL server, and the schema
folder separates each resource into separate files. lib
contains database
The infrastructure code is stored in the terraform
folder. Most of the files are separated by service, although autoscaling, security, and networking are grouped by functionality instead. The application is Dockerized and shipped on AWS Fargate through CircleCI.
-
Improve the mechanism to determine bomb distribution. The current random implementation could lead to unsolvable and/or boring games.
-
Improve the board-drawing algorithm, potentially adding a
Board
type to both GraphQL and Postgres. The separation of concerns between Game and Square are blurred, and the algorithm is too mutative. -
Improve db mocking, as the current implementation isn't flexible enough to handle multiple db calls effectively
-
Set up a branch workflow in CI that will deploy feature branches to a separate cluster for testing
-
Expose a query for the
Square
type, and add filter arguments for thegames
query. -
Oh, and a frontend