The Project
The overview section for REST can be found here. The setup instructions for REST are here. Read on for details on the REST Candy project.
Candy
This FiveThirtyEight article explores a data-driven approach to understanding candy. We downloaded a snapshot of the data. You can read more about the data here about which candy is better, along with nutritional information and price. In this project, let’s assume that our RESTful API is maintaining this dataset on an ongoing basis.
A starter database schema would look like this:
DROP TABLE IF EXISTS candy;
CREATE TABLE candy(
id SERIAL PRIMARY KEY,
competitorname TEXT,
chocolate BOOLEAN,
fruity BOOLEAN,
caramel BOOLEAN,
peanutyalmondy BOOLEAN,
nougat BOOLEAN,
crispedricewafer BOOLEAN,
hard BOOLEAN,
bar BOOLEAN,
pluribus BOOLEAN,
sugarpercent DECIMAL,
pricepercent DECIMAL,
winpercent DECIMAL
);
You can use an PostgreSQL COPY
command to copy this into the table directly. Or you can adapt the code for Bechdel to do a batch import via psycopg2.
REST1: Basic Resources and Resource Methods
We will still be following the merge request and tagging pattern. Please tag your code as rest1
on the master branch when it is merged.
In this initial iteration, we’re looking to get the basics working. In particular, we’ll be looking at getting a few types of resource methods working, to perform the following functions
- List All Keys,
- List All Candy, and
- Show Candy Details.
These are not the actual APIs, they are the descriptive names of the functionality provided by the APIs.
Remember that RESTful APIs operate on resources. In the case of Candy data, the resource is the candy data itself.
The APIs, will be various operations on the candy data. For example:
List All Keys will return all of the data as primary keys; The api could look like/candy/keys
List All Candy shows essentially the entire table, and could look likecandy/
Show Candy Details will give the details about one row based on the primary key provided, and could look like `/candy/{id}.- Note that the id could be provided in the URL or as a query string
To do this, you will need to determine and name your resources, and then create endpoints and resource methods for those resources. All responses must be in JSON format and follow the RESTful guidelines.
Grading REST1 ( 40 points)
- (15pts) APIs correctly implemented
- (15pts) Test cases implemented & pass
- (05pts) RESTful API standards followed
- (05pts) Good code maintainability and quality
REST1 Candy
Beware of decimal conversion between PostgreSQL, Python, and JSON via HTTP. Reviewing how Decimal
works in Python and psycopg2 may be worth your time.
Test Case Sketches
- When using List All Keys, I should get 85 different keys
- When I list List All Keys and List All Candy, I should get the same count
- When I use List All Candy, the results should have an entry with the data from the
Baby Ruth
column, including the same digits of precision. - If I use Show Candy Details on
Baby Ruth
, I should get the data from that row, including all digits of precision
REST2: CRUD and Authentication
Create a branch rest2-dev
. Please tag your code as rest2
on the master branch when it is merged.
This iteration, you will need to provide only two basic CRUD operations to your data: create and delete. Add those actions to your RESTful API using those conventions.
However, we can’t let just anyone come into the system and make changes, so we need to also provide authentication. Let’s assume that there is a separate way to set and reset accounts. You’ll implement just the core functionality: logging in and logging out - but will thorough testing of ‘happy path’ and ‘problem’ scenarios. From the client side, this will look like this:
- Send a POST request to your login endpoint with a username and password.
- The username/ password should be in the BODY of the POST request
- System returns a message that your login was successful and gives you a session key, which is a large random number that nobody should be able to guess.
- When attempting to do a CRUD operation, the operation will only work if your request also has the session key. The session key should be sent in the HEADER of each subsequent API call
- If you send a request to the logout endpoint, then subsequent CRUD operations won’t work. Note that you must be logged in to trigger a logout, otherwise anyone can log you out!
You will create a users
table with a username
, password
, and session_key
field in your database. Your test data should have a user already registered. However, we must store our passwords securely. This means using a one-way encryption function called a hash digest . You can read more about hash digests and salts over on the Common Weakness Enumeration CWE-759. In pseudocode, the way you would compute the hash digest of a password would be: hashed_password = hash(password)
For this project, we’d like you to use the SHA-512 hash digest algorithm. Find a secure way to generate a session key within your technology choice as well, not just the default random number generator for your language.
From the server side, authentication would look like this:
- Client sends a request with their username and password to the login endpoint
- Server computes the proper hash digest of the password
- Server checks if that digest exists in the database table with that username
- If so, generate a secure session key. (Otherwise, return a message that login was not successful)
- Save the session key to the user’s record in the database
- Return a success message with the session key
For Python, these resources will be helpful:
- Python’s hashlib for SHA-512 digest function
- Python’s secrets for generating a session key
- Online SHA512 calculator for sanity testing
Grading REST2 (70 points)
- (20pts) CRUD operations work
- (10pts) Authentication feature works
- (30pts) Test cases implemented and pass
- (05pts) RESTful API standards followed
- (05pts) Good code maintainability and quality
Key Decisions
- What are the conventions for CRUD operations based on your existing resource?
- Does it make sense to refactor the meaning of your resource to better fit RESTful conventions?
- What will be the structure of the APIs? How will you pass the arguments?
REST2 Candy
Test Case Sketches
In each test case, print out (clearly), the test being run and the result of the test. If there are multiple steps in a test case, list the steps/ results as they occur. Make sure you handle the results without crashing!
- Login test cases.
- Create a new user accout. Validate it is created
- Try to login with a non-existent account
- Try to login with a valid user but invalid password
- User
jason
already has an account with the passwordhalloween
. Theusers
table initially has a row with usernamejason
, and the hashed (sha512) result of the password! An HTTP request is sent in to the login endpoint withjason
andhalloween
as the credentials. A large session key is sent back. - Nobody is logged into the system. An HTTP request makes an attempt to delete
Chiclets
, and the system does not do the action because nobody is logged in.- Note: To safely delete a record, you should get the record for
Chiclets
, then use the primary key from that query to try and delete the record.
- Note: To safely delete a record, you should get the record for
- The above test case happens, but log in first and then the delete occurs correctly when the given session key is provided.
- Logout test case. The login test case is first run, then a request to the logout endpoint occurs, providing the given session key. An HTTP delete is attempted and fails.
- Unauthenticated logout. Log in with the test case above. Attempt to log out without providing a session key. All users remain logged in.
- Try to logout a user who is not logged in
- A new candy is added,
Bertie Botts Beans
. It’s a candy delight, despite it’s odd froggy flavor. - An update to a Candy is needed, when people realize that
Haribo Twin Snakes
is made from real snakes. The new winrate is20.1
(Apparently some people don’t care).