Lab API #
In this lab we are going to learn how the riddle server is made using Banjo.
[0] Experience the ISF Riddle Server #
The last time we saw riddles, they existed only within each of your computers. You had to manually add new ones and there was no way to keep track of how many people guessed them.
We are now going to look at Riddles that are hosted on the internet!
π» Visit http://sycs.student.isf.edu.hk/riddle/all to view riddle server.
Not very easy to read, right? You can install the JSON Formatter Chrome extension to view better formatted JSON.*
π»
Now try making GET
request to http://sycs.student.isf.edu.hk/riddle/all
receive the same information using :
httpie.io/app

π»
Do you know the answer? Try sending a POST
request to make a guess. This request to a different url endpoint
: /guess
- Add a new request
- Change
GET
toPOST
- Paste in the URL:
http://sycs.student.isf.edu.hk/riddle/guess
- Select
Body
- At the bottom, change
None
toForm
- Add the payloads:
id
andguess

It is common for
POST
requests to send a payload with the request. In this case, the payloads are:
id
specifying which riddle we are guessingguess
specifying the guess We are also sending this request to a different urlendpoint
:/guess
Explore the Endpoints #
π Server APIs often rely on different URL endpoints to the base url to determine what the API should do.
- The base url to this server is:
http://sycs.student.isf.edu.hk/riddle
Here is a cheatsheet of the Riddle endpoints, what parameters they take in their payload, and what they do:
Method | URL | Required Payload | Action |
---|---|---|---|
GET | /all | Returns a list of all the riddles, without answers. | |
GET | /one | id | Returns the riddle if it exists |
POST | /new | question , answer | Creates a new riddle (with an automatically-assigned id). Returns the riddle. |
PUT | /guess | id , guess | Checks whether the guess is correct. In the response, correct is True or False . |
GET | /difficulty | id | Returns the riddle if it exists with its difficulty score. (Otherwise, it returns an error with status code 404.) |
β CHECKPOINT:π» Explore each endpoint in the
httpie tool
, and be sure to successfully:
- view all riddles without the answers
- view a single riddle
- add a new riddle
- guess a riddle
- try to break the riddle server, what happens when you provide incorrect parameters?
π When using the the httpie tool,
- for a
GET
request, put the payload in theParams
- for a
POST
request, put the payload in theBody
>Form
[1] Set Up #
π» Download Mac app of HTTPIE: httpie.io/download. We need to download the app to make local HTTP requests for testing purposes.
π» Start by going into the unit folder and the lab.
Remember to replace yourgithubusername
with your actual GitHub username.
cd ~/desktop/making_with_code/unit03_networking/
git clone https://github.com/the-isf-academy/lab_apiyourgithubusername
cd lab_api_yourgithubusername
poetry install
poetry shell
This server is written using the Flask Library. It allows easily write an API to interact with a SQL databse.
π Our API has a few main files api.py
helpers.py
.
api.py
- API strucutre where endpoints are definedhelpers.py
- helper functions to interact with databasedatabase.db
- riddles SQL database
[2] Local Riddle Server #
Your computer can host a local server
that accessess the riddle API
.
π» Now, let's start your local server:
python api.py
. This will run a local server that is only accessible on your local computer.
π» You can now visit this server in your web browser, just as you did with the riddler server hosted on the internet: 127.0.0.1:8000/riddle/all
π» Open the HTTPie
desktop app to send the same GET
request to /all
.

[16/Sep/2024 02:44:20] "GET /riddle/all HTTP/1.1" 200 1069
Hitting the Server #
π» Send a POST
request to the /new
endpoint.
Payload:
question
(str)answer
(str)

[01/Sep/2024 20:56:22] "POST /riddle/new?id=1 HTTP/1.1" 200 127
Your version of the riddle server only has the 2 endpoints:
/riddle
/riddle/all
/riddle/new
β CHECKPOINT:π» Explore both endpoints via the HTTPie desktop app and be sure to successfully:
- view all riddles without the answers
- create a new riddle
[3] Writing Routes #
In this lab, you will build out the functionality of the Riddle server. Currently, your file only has riddle/all
and riddle/new
.
It is up to you to add the following endpoints:
riddle/one
riddle/random
riddle/guess
π» Start by opening up the folder:
code .
You should first, open a new terminal tab with
β + T
, so you can keep your server running in one tab, and use the other tab to access your filesystem
π»
Open the api.py
file. Here is where you will write the additional endpoints.
π First, take a look at the index()
function.
|
|
line 1
- defines the URL route and the HTTP request typeline 2
- defines a function and any necessary parametersline 3
- defines the JSON responseline 4
- returns the JSON and the HTTP response code
HTTP response codes #
The important HTTP success response codes
200
- successful GET or PUT request201
- successful POST request
riddle/one #
π»
Write the riddle/one
endpoint.
- HTTP method:
get
- Payload/args:
id
- Return: a single
Riddle
with thequestion
,guesses
, andcorrect
properties
π€ Which functions
in `helpers.py`` could be useful?
β CHECKPOINT:π» Test the
riddle/one
endpoint in theHTTPie desktop app
http://127.0.0.1:8000/riddle/one id=4
βοΈ It should return
json
like:{ "riddle": { "id": 1, "question": "Iβm light as a feather, yet the strongest person canβt hold me for five minutes. What am I?", "total_guesses": 43, "correct_guesses": 0 } }
riddle/random #
π»
Write the riddle/random
endpoint.
- HTTP method:
get
- Payload/args: none
- Return: a single
Riddle
with theid
,question
,correct
, andguess
properties
π€ Which query method may be useful? Be sure to reference the Banjo documentation.
β CHECKPOINT:π» Test the
riddle/random
endpoint in theHTTPie desktop app
http://127.0.0.1:8000/riddle/random
βοΈ It should return
json
like:{ "correct_guesses": 0, "difficulty": 0, "id": 219, "question": "What is full of holes, but can still hold a lot of water?", "total_guesses": 0 }
riddle/guess #
π»
Write the riddle/guess
endpoint.
- HTTP method:
put
- Payload/args:
id
andguess
- Return:
- if the guess was correct
- message telling the user they were correct
- a single
Riddle
with all of row values
- if the guess was incorrect
- message telling the user they were incorrect
- a single
Riddle
without the answer
- if the guess was correct
π€ Which functions
in `helpers.py`` could be useful?
β CHECKPOINT:π» Test the
riddle/guess
endpoint in theHTTPie desktop app
http://127.0.0.1:8000/riddle/guess
βοΈ It should return
json
like:{ "correct": true, "riddle": { "answer": "Noon", "correct_guesses": 14, "difficulty": 0.8235294117647058, "id": 3, "question": "What time of day, when written in a capital letters, is the same forwards, backwards and upside down?", "total_guesses": 17 } }
[4] Deliverables #
β‘β¨Once you’ve successfully completed the worksheet be sure to fill out this Google form.
π» Push your work to Github:
- git status
- git add -A
- git status
- git commit -m “describe your code and your process here”
be sure to customize this message, do not copy and paste this line
- git push
[5] Extensions #
Error Messaging #
Try to access a riddle that does not exist. You get an error, correct? A better solution is to return an error message with helpful information.
The HTTP code for an erorr is 404
. You are probably familiar with this from surfing the web.
Here is an example of an error message:
if riddle is None:
return {'error': 'Post not found'}, 404
if not question or not answer:
return {'error': 'Question and Answer are required.'}, 400
Incorporate approprate error messages for each of your endpoints. Try to break them.
The important HTTP success response codes
400
- incorrect payload404
- no results found
Difficulty #
Since that we track difficulty
, it would be nice if we could GET
a list of riddles of easy
, medium,
or hard
difficulty.
π»
Write a function get_riddles_difficulty(level)
that returns all of the riddles within the appropriate range.
- reference SQL WHERE operators
- consider what the difficulty ranges should be for easy, medium, hard (difficulty of 1 is impossibly hard, while a Riddle with a difficulty of 0 is easy)
π» Write an endpoint returns riddles within a difficulty category
- HTTP method:
GET
- Payload/args:
level
- Return:
- a list of
Riddles
with theid
,question
,correct
, andguess
properties of the designated difficulty level
- a list of
You can use an url parameter like:
@app.route(f'/{BASE_URL}/all/<str:difficulty>', methods=['GET'])
def all_riddles_difficulty(difficulty):
βοΈ It should return json
like:
{
"difficulty_level": "hard",
"riddles": [
{
"correct": 1,
"guesses": 44,
"id": 1,
"question": "Iβm light as a feather, yet the strongest person canβt hold me for five minutes. What am I?",
"difficulty": 0.9555555555555556
},
{
"correct": 4,
"guesses": 9,
"id": 2,
"question": "What comes down but never goes up?",
"difficulty": 0.875
}
]
}