Introduction
The Code Words API is an API for playing the game Code Words. It is built as a compliment to Code Words Web, a web client-based React project, with the aim of potentially creating something in React-Native or Swift to consume this same API at some future date.
Models
Database models should be consistently serialized regardless of the endpoint.
Game
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"activePlayerId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"board": [
// see Game.board
],
"completed": false,
"started": true,
"turns": [
// see Game.turns
],
"players": [
// See Player
]
}
The Game model is the major model in Code Words. It contains all sorts of stuff, including most importantly, board
and turns
.
Enumerated values:
Game.board
Example turns:
{ "word": "waffle", "revealed": true, "type": "b" },
{ "word": "pancake", "revealed": false, "type": "redacted" },
{ "word": "chowder", "revealed": true, "type": null }
The Game's board
is an array of 25 Objects describing the 5 ⨉ 5 grid of tiles (in a simple list,
no grid in serialization) with their words, whether they've been revealed, and what their
type is.
- If the User is playing a
'transmitter'
,type
will never be'redacted'
even ifrevealed
istrue
. - If the User is playing a
'decoder'
,type
will be'redacted'
if the tile is not yetrevealed
.
Enumerated values:
type
:null
,'a'
,'b'
,'x'
,'redacted'
Game.turns
transmission
turn:
{
"event": "transmission",
"number": 2,
"playerId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"word": "breakfast"
}
decoding
turn:
{
"correct": true,
"event" "decoding",
"playerId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"tile": 12
}
end
turn:
{
"event": "end",
"winner": "a"
}
The Game's turns
are an array of the turns taken thus far in the game. There are three possible
types of turns, indicated by the turn Object's event
attribute. The other attributes will change
based on the event
being described.
- The
transmission
event contains the word and number submitted from the Transmitter. - The
decoding
event contains the tile chosen to decode, and whether or not the tile belonged to the team of the Decoder indicated incorrect
. - The
end
turn signifies that a game has ended, either by all of one team's tiles being revealed, or the'x'
tile being selected. It indicates the winning team.
Enumerated values:
event
:'transmission'
,'decoding'
,'end'
winner
(for'end'
event):'a'
,'b'
User
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"username": "my-username"
}
The User model is currently very simple. When serialized, it just had an id
and
a username
, both strings.
Player
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"gameId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"role": "transmitter",
"team": "a",
"user": {
// See User
}
}
The Player model joins Users and Games. It also contains information about how the
player relates to the game. Both the role
and team
attributes begin as null
,
and are assigned before a game is started.
Enumerated values:
role
:null
,'transmitter'
,'decoder'
team
:null
,'a'
,'b'
Authentication
Authentication is managed with a signed JSONWebToken received during Signup or Login. To access authenticated routes, this token must be passed along in one of the following ways:
- Bearer authorization: pass the
Authorization
HTTP header in the format "Bearer xxxxxxxxxx…" - GET or POST parameters: pass the token as
access_token
POST /signup
Example JSON body for
/signup
:
{
"username": "my-username",
"password": "my-password"
}
Responds with login JSON
The Sign Up endpoint expects a JSON body with username
and password
keys. The username
must be between six and 24 characters, and consist of letters, numbers, dashes, and periods. The password
must be between seven and 50 characters and has no character restrictions.
Upon successful signup, the user is logged in and granted a token. See POST /login
for return value.
POST /login
Example JSON body for
/login
:
{
"username": "my-username",
"password": "my-password"
}
Responds with JSON:
{
"token": "…",
"user": {
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"username": "username"
}
}
token
is a JSONWebToken containing a payload withuserId
The Log In endpoint expects the same type of JSON body as Sign Up, and returns the same type of response (since both log a user in).
Games
All Games routes are authenticated.
GET /api/v1/games
: index
Expects no params.
Returns list of serialized Games.
Returns a list of Games.
POST /api/v1/games
: create
Expects no params.
Returns serialized Game.
Creates a new Game for the credentialed User. Returns the Game, serialized.
GET /api/v1/game/:gameId
: show
Expects no params besides URL param.
Returns serialized Game.
Returns a serialized Game record based on the id in the URL.
POST /api/v1/game/:gameId/start
: start
Expects no params besides URL param.
Returns serialized Game.
Attempts to start a Game. This assigns the activePlayerId
which will have previously
been null
. With an activePlayerId
, the associated Player is now eligible to take her
turn. Returns the serialized Game.
PUT /api/v1/game/:gameId/transmit
: transmit
Expects JSON body:
{
"word": "clue",
"number": 3
}
Returns serialized Game.
Endpoint to take turn for Player of role
'transmitter'
. Updates the activePlayerId
and
returns the serialized Game.
word
must be a single word. number
must be between 1
and the number of remaining tiles
un-revealed for the team.
PUT /api/v1/game/:gameId/decode
: decode
Expects JSON body:
{
"tile": 12
}
Returns serialized Game.
Endpoint to take turn for Player of role
'decoder'
. Updates the activePlayerId
if
tile is incorrect and returns the serialized Game.
tile
is the index of the chosen tile on the Game's board
, and thus must be a number
between 0 and 24. It also cannot be the index of a tile that's already revealed.
PUT /api/v1/game/:gameId/end-turn
: endTurn
Expects no params besides URL params.
Returns serialized Game
If a decoder
Player does not wish to make any more decoding
turns, she may
end her turn at this endpoint, advancing the activePlayerId
to the next player.
POST /api/v1/game/:gameId/rematch
: rematch
Expects no params besides URL params
Returns new serialized Game
Can take the id
of a completed Game and create a new game with the same players. It
swaps the players’ teams and roles, but does not automatically start the new game. Teams
can still be reorganized (and players removed for different players).
DELETE /api/v1/game/:gameId
: destroy
Expects no params besides URL params.
Returns 200 status, empty JSON body.
Endpoint to delete a Game. Game cannot be deleted if it is already started. Does not return a body because if it's successful there's nothing to serialize.
Players
All Players routes are authenticated.
POST /api/v1/game/:gameId/players
: create
Expects JSON body:
{
"username": "my-username"
}
Returns serialized Game
Creates a new Player for the User with the requested username
on the specified Game, and returns that Game, serialized.
PUT /api/v1/game/:gameId/player/:playerId
: update
Expects JSON body with at least one of the following keys:
{
"team": "a",
"role": "decoder"
}
Returns serialized Game
Updates the specified Player to assign him to a team and/or role. Returns updated Game, serialized.
DELETE /api/v1/game/:gameId/player/:playerId
: destroy
Expects no params besides URL params.
Returns 200 status if authenticated User's Player was destroyed; returns serialized Game if it was another User's Player.
Deletes association between User and Game. Can only be done if Game is not yet started. If the User removed her own Player, a 200 status is returned. If the User removed another Player, the updated, serialized Game is returned.
WebSockets Messages
WebSockets are authenticated using access_token
in the query string, and
connected at /api/v1
through the ws://
protocol.
On successful connection, GAMES_INDEXED
is emitted.
GAMES_INDEXED
Emits JSON:
{
event: 'GAMES_INDEXED',
payload: {
games: [
// list of Games for authenticated User
]
}
}
Emitted on successful connection.
GAME_UPDATED
Emits JSON:
{
event: 'GAME_UPDATED',
payload: {
// serialized Game object
}
}
Emitted to all connected WebSockets for a Game except the initiating User when a Game is updated in any way.