REST API


Overview

REST is a standard or convention for defining web services. It is very closely associated with HTTP, though in theory it could be used with different protocols. REST defines resources (think objects or entities) and methods that operate on them. Specifically, the methods are to create, read, update, and delete (C.R.U.D.) these resources.

In practice, there are different versions and options associated with REST. For this project, the four operations are defined in the following table.

Operation REST/HTTP Method Corresponding SQL Description
C POST Insert Creates an instance of the resource
R GET Select Views the a resource
U PUT Update Updates the resource
D DELETE Delete Deletes an instance of the resource

Ladder API

For each of the ladder entities defined here, the CRUD operations are defined by the following tables. If additional parameters are given, they should be ignored. The error text will not be checked for anything specific, return something sensible. You may add additional functionality to the API if it is useful for your HTML/JS client, however do not remove or alter what is described here.

The resources for this project are player, match, and challenge. For example, the URL for the player resource will be http://yourdomain.com/player. The parameters for each resource method, should be a map unless otherwise specified i.e. username should be implemented as {"username":"bucko"}.

Methods for Player
Operation Behavior Parameters Response Example Response
C Create a new player. The player's rank should be automatically be assigned the highest value not yet taken. {name, email, phone, username, password} http status - 202 if the player was successfully added otherwise 400, error_text - a message describing the error. Ensure that the phone and email are valid and the username is unique. {"error_text":""}
R Returns the player with the given username {username} http status - 200 if the request is good e.g. a username is given, otherwise 400. The JSON response should be an entry "player" populated by an object with name, email, rank, username, and phone. The "player" should be empty if there is no player that matches "{"name":"Pete",
"email":"pete@georgefox.edu",
"rank":5,
"username":"bucko",
"phone":"5554443333",
"match_win_percentage":.83, "game_win_percentage":.94, "winning_margin":4.1, "losing_margin":1.1}
U Updates the player with the given parameters. All the players between the old and new rank need to be shifted either up or down depending on the change. {username, name, email, rank, phone} http status - 200 if the request is good, otherwise 400. error_text - describes any problems with the update e.g. bad phone number or email {"error_text":"Phone number was not formatted correctly"}
D Deletes the player. Other players ranks may need to be adjusted. Outstanding challenges and games should be removed. {username} http status - 200 if the player was deleted otherwise 400. error_text - again a message describing the error {"error_text":"player does not exist"}

A valid phone number is 10 digits and a valid email should be of the form _____@____.___


Methods for Match
Operation Behavior Parameters Response Example Response
C Creates a new match i.e. a group of new games, based on the list of parameters. The number field should be automatically incremented based on the order the game is in the list. The players' ranks should updated after the games are created. If the lower ranked person beats the higher ranked person, the lower ranked person moves up to the defeated person's rank. The defeated person, along with any players in between move down one rank. If the higher ranked person wins, neither person's rank changes. Also, only two usernames should be used across all the games added in a single operation. { games:[{winner, loser, winner_score, loser_score}], played} http status - 202 if the games were successfully added otherwise 400, error_text - a message describing the error {"error_text":"winner does not exist"}
R Returns the match, i.e. all the games, where the player is the winner or the loser. Also, the parameter played is optional, if included, the read operation should return all the games where player is the winner or loser and were played on that date and time. {username, played*} http status - 200 if the request is good i.e. the fields can be parsed, otherwise 400. games - a list of objects with winner, loser, played, number, winner_score, loser_score fields [{"winner":"bucko", "loser":"ted", "2018-08-10", "number":1, "winner_score":10, "loser_score":5},

{"winner":"bucko", "loser":"ted", "2018-08-10", "number":2, "winner_score":15, "loser_score":8}]
U No implementation need
D Delete the match that matches all the fields. The given players can be either the winner or the loser of the game, but both players must be involved. The player's ranks should not be adjusted. {player1, player2, played} http status - 200 if a match is deleted, otherwise 400. error_text - a message describing the error {"error_text":"match does not exist"}

Note, the 'played' field should be in the ISO 8601 format. For example, the date October 29th, 2018 at 2:48 PM is represented as 2018-10-29 14:48.

Curl command to make a request to add a match:

curl -X POST -H "Content-Type: application/json" localhost/314-ladder/match/ -d '{"games":[ {"winner":"rmills1", "loser":"eprice2", "winner_score":10, "loser_score":9}, {"winner":"rmills1", "loser":"eprice2", "winner_score":10, "loser_score":8}, {"winner":"eprice2", "loser":"rmills1", "winner_score":10, "loser_score":9} ], "played":"2019-11-05 10:24"}'


Methods for Challenge
Operation Behavior Parameters Response Example Response
C Creates a challenge between players, scheduled at the given date. The newly created challenge is "issued" at the current time. Also, challenges are only accepted later via update. The combination of challenger, challengee, and scheduled must be unique. Finally, a player can only challenge another player:
  • Who are at most ranked 3 spots above (e.g., player #5 can challenge 2, 3, and 4)
  • Who are not ranked below them (since this doesn't really make sense)
  • Who are not a party to an outstanding challenge that has been accepted
{challenger, challengee, scheduled} http status - 202 if the challenge is created, 400 otherwise, error_text - a message describing the error {"error_text":""}
R Returns a challenge if the player is involved as either the challenger or challengee {player} http status - 200 if the request is good, 400 otherwise, error_text - a message describing the error, challenge - a object with all the challenge fields, or empty if the player is not involved {"challenges":[
{"challenger":"bucko", "challengee":"ted", "issued":"2018-08-17", "accepted":"2018-08-31", "scheduled":""
}]}
R An alternative challenge read operation, if the "challenger" parameter is given, return players available for that player to challenge. The "challenger" field should contain a username. {challenger} http status - 200 if the request is good, 400 otherwise, error_text - a message describing the error, candidates is a list of players available to challenge {"candidates":[
{"name":"Pete", "email":"pete@georgefox.edu", "rank":1, "phone":"5553334444", "username":"bucko"},

{"name":"ted", "email":"ted@georgefox.edu", "rank":2, "phone":"5553334445", "username":"ted"}]}
U Updates the challenge based on the parameters. Updates the accepted field. Also, all other outstanding challenges involving the challenger and challengee must be deleted. {challenger, challengee, scheduled, accepted} http status - 200 if the request is good, 400 otherwise, error_text - a message describing the error {"error_text":"challenge does not exist"}
D Deletes the challenge between the players {challenger, challengee, scheduled} http status - 200 if the challenge was deleted, 400 otherwise, error_text - a message describing the error {"error_text":"challenge does not exist"}

Again note, that the 'schedule' and 'accepted' fields should be in the ISO 8601 format. For example, the date October 29th, 2018 at 2:48 PM is represented as 2018-10-29 14:48.

Authentication

For authentication, a REST-Like API will be used. The purpose is to establish a session prior to using the other resources. The url for this resource will be http://yourdomain.com/login. After milestone 4, a http status of 401 should be returned if access of resource is attempt before logging in.

Methods for Login
Operation Behavior Parameters Response
C Establish a server side session with valid username, password combination {username, password} http status - 200 if login was successful, 400 if there is an error, or 403 if login denied
R Returns the username of the current logged-in user Returns a JSON object with the username of the current user and http status - 200 if a user is logged in. Returns http status 403 if no one is logged-in.
D Ends the server side session for the currently logged-in user http status - 200 if logout was successful, 400 if there is an error

Note, the create operation for player should not be authenticated.

Starter Files

Some useful starter files are found here. The zip contains a file with a PHP class to handle and properly parse HTTP requests for our REST API. The python file contains a framework to test the API. Note, it was written for python 2.7


API Usage Examples


Creating a player

To create a player, a POST request should be sent to URL http://mydomain.com/player. The contents of the request is the JSON string:

{"name":"Walker", "email":"jorr@georgefox.edu", "phone":"555-5555", "username":"drwalk", "password":"qaz123"}
Assuming there is no problem with the request, the reponse will have a status code of 200 and a JSON string:
{"error_text":""}


Viewing a player

To view a the player "drwalk", a GET request should be the URL http://mydomain.com/player&username=drwalk. For GET requests, there is no request body, the only parameter is encoded in the URL. The response however will still be in JSON format:

{"name":"Walker", "email":"jorr@georgefox.edu", "phone":"555-5555", "username":"drwalk", "rank":12, "match_win_percentage":.68, "game_win_percentage":.76, "winning_margin":2.1, "losing_margin":1.8}


Viewing a non-existant player

Let's say that you try to view a player that does not exist in the application. For example, the if request to the URL http://mydomain.com/player&username=drbrian, you should receive a response with HTTP status code 400 and a response like:

{"error_text":"drbrian does not exist"}
However the error message does not need to exactly match the example, but it should be something reasonable.


Updating a player

Updating a player is similar to creating one. If we want to update the email address of "drwalk," all the player's fields need to be sent again in addition to the new email address. To update, send a PUT request to the URL http://mydomain.com/player with the a JSON string:

{"name":"Walker", "email":"drmeme@georgefox.edu", "phone":"555-5555", "username":"drwalk"}
Note that the username of a player cannot be changed even with an update, since the system will need the given username to lookup the existing player. You should expect a response with an HTTP status code of 200 and a JSON string:
{"error_text":""}


PDO Example Code

Here is an example for using PDO to read from the player table. You'll want to split out the database connection code into it's own php file.

try
{
	$db = new PDO("pgsql:dbname=ladder host=localhost password=YOURPASSWORDHERE user=YOURUSERNAME");
	$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $err)
{
	exit("Database error!");
}

$sql = "select * from player where username = ?";

$statement = $db->prepare($sql);

$username = "rmills1";

#run the query
$statement->execute([$username]);

#get the results
$results = $statement->fetchAll(PDO::FETCH_ASSOC);	

#show the number of rows effected
echo "Rows: " . $statement->rowCount() . "<br />";

foreach($results as $row)
{
	$username = $row["username"];
	$rank = $row["rank"];
	$name = $row["name"];
	
	echo "$name, $username, $rank <br />";
}
			

Here is a similar example with named placeholders instead of positional ones

try
{
	$db = new PDO("pgsql:dbname=ladder host=localhost password=YOURPASSWORDHERE user=YOURUSERNAME");
	$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $err)
{
	exit("Database error!");
}

$sql = "select * from player where username = :username";

$statement = $db->prepare($sql);

$username = "rmills1";

#run the query
$statement->execute(["username" => $username]);

#get the results
$results = $statement->fetchAll(PDO::FETCH_ASSOC);	

#show the number of rows effected
echo "Rows: " . $statement->rowCount() . "<br />";

foreach($results as $row)
{
	$username = $row["username"];
	$rank = $row["rank"];
	$name = $row["name"];
	
	echo "$name, $username, $rank <br />";
}
			

This page was last modified on 2019-11-05 at 10:52:02.

Copyright © 2018–2019 George Fox University. All rights reserved.