berserkware
Posted on August 8, 2022
In this tutorial we will be creating an API to give you debate topics. We will be building the API with Waffleweb.
For those who don't know Waffleweb is a Python web framework. It is lightweight and highly customizable. You can find Waffleweb at https://github.com/Berserkware/waffleweb.
Prerequisites
To create the API you will need Python and Waffleweb installed. Since there are many tutorials on how to install Python available, You will only been shown how to install Waffleweb.
Installing Waffleweb
Installing Waffleweb is easy with pip.
pip install waffleweb
Setting Up the Project
To set up your project all you need to do is create a main.py file. The main.py file is the file that has all your routes. It also runs the webserver. For now it just need to have to following code.
main.py:
from waffleweb import app
#Runs the built-in webserver.
if __name__ == '__main__':
app.run()
Creating the Basic Pages
The basic pages will educate your users on what the API does, and how to use it. To start creating the basic pages we first need to create some templates.
Creating the Files Needed
Let's start by creating a folder named "templates" and putting two files in it: "index.html" and "usage.html". We will put some data in these files. These pages are pretty basic, so customize as you please.
templates/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Debate API</title>
</head>
<body>
<h1>Welcome to the Debate API!</h1>
<h2>Usage: <a href="/usage">Usage</a></h2>
<h3>Debate of the Day:</h3>
<h2>{{ debateOfTheDay }}</h2>
</body>
</html>
templates/usage.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Debate API Usage</title>
</head>
<body>
<h1>Debate API Usage</h1>
<h2>/api/random</h2>
<p>Gets a random debate topic.<br>Returns:</p>
<code>
{"topic": "[Insert Topic Here]", "id": id}
</code>
<h2>/api/{id}</h2>
<p>Gets a debate topic by ID.<br>Returns:</p>
<code>
{"topic": "[Insert Topic Here]", "id": id}
</code>
<h2>/api/debate-of-the-day</h2>
<p>Gets the debate topic of the day.<br>Returns:</p>
<code>
{"topic": "[Insert Topic Here]", "id": id}
</code>
</body>
</html>
We also need to create a folder called "data" and add a file called "data.json". We also need to populate it with some boilerplate data. We will also add some debate questions. The debateOfTheDay should be the index of the debate of the day.
data/data.json:
{
"topics": [
"Nuclear energy is the best energy.",
"Python is the best programming language.",
"Social media is unhealthy.",
"Apples are the best fruit."
],
"debateOfTheDay": 0
}
Routing the Functions
Now we need to route the functions to return the page. We can do this easily by using the route
decorator. The index page will have some extra logic to retrieve the debate of the day.
main.py:
from waffleweb import app
from waffleweb.response import render
import json
@app.route('/')
def index(request):
with open('data/data.json', 'r') as f:
#Gets the data and loads it into a dictionary
data = json.loads(f.read())
#This gets the id of the debate of the day then finds the matching topic
debateOfTheDay = data['topics'][data['debateOfTheDay']]
return render(request, 'index.html', {'debateOfTheDay': debateOfTheDay})
@app.route('/usage')
def usage(request):
return render(request, 'usage.html')
#Runs the built-in webserver.
if __name__ == '__main__':
app.run()
The only argument the route
decorator is the URL to access that page. The render
function returns a template.
You can now test the pages by running the "main.py" file.
Creating the API
To create the API section of your site, all we need to do is route some functions. We will be routing three pages, one for a random topic, one for the debate of the day and one to get a topic by its ID.
Routing the Functions
To route the function we will, again, use the route
decorator.
main.py:
from waffleweb import app
from waffleweb.response import render, JSONResponse
import json
import random
@app.route('/')
def index(request):
with open('data/data.json', 'r') as f:
#Gets the data and loads it into a dictionary
data = json.loads(f.read())
#This gets the id of the debate of the day then finds the matching topic
debateOfTheDay = data['topics'][data['debateOfTheDay']]
return render(request, 'index.html', {'debateOfTheDay': debateOfTheDay})
@app.route('/usage')
def usage(request):
return render(request, 'usage.html')
@app.route('api/random')
def randomTopic(request):
with open('data/data.json', 'r') as f:
#Gets the data and loads it into a dictionary
data = json.loads(f.read())
topics = data["topics"]
randomTopicID = random.randint(0, len(topics))
return JSONResponse(request, {"topic": topics[randomTopicID], "id": randomTopicID})
@app.route('api/debate-of-the-day')
def debateOfTheDay(request):
with open('data/data.json', 'r') as f:
#Gets the data and loads it into a dictionary
data = json.loads(f.read())
#This gets the id of the debate of the day then finds the matching topic
debateOfTheDayID = data['debateOfTheDay']
debateOfTheDay = data['topics'][debateOfTheDayID]
return JSONResponse(request, {"topic": debateOfTheDay, "id": debateOfTheDayID})
@app.route('api/<id:int>')
def getTopicByID(request, id):
with open('data/data.json', 'r') as f:
#Gets the data and loads it into a dictionary
data = json.loads(f.read())
topics = data["topics"]
if type(id) != int:
return JSONResponse(request, {"error": "The ID has to be an int."})
if id < 0 or id >= len(topics):
return JSONResponse(request, {"error": "A topic with that id does not exist."})
return JSONResponse(request, {"topic": data["topics"][id], "id": id})
#Runs the built-in webserver.
if __name__ == '__main__':
app.run()
In the route for getting a topic by id you might notice a strange bit of text in it: "<id:int>
". This is an URL variable that allow us to have variable parts in your URLs. We can then access the variables as function arguments.
The JSONResponse
is a response specifically for JSON.
Conclusion
Thanks for reading this tutorial! I hope you had success following this tutorial. Feedback is much appreciated!
Posted on August 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.