💻 Week 02 Lab
Building APIs with FastAPI (Part I)

Last Updated: 27 January 17:30 to incorporate ideas from the morning session.
📋 Preparation
Before attending this lab, ensure that you:
Have completed the 📝 W01 Formative Exercise, which focused on creating alternative visualisations of the ASCOR EP Pillar. This should help you familiarise yourself with the dataset we are using.
Have reviewed the lecture content from Week 02, particularly the FastAPI Overview, RESTful Design Principles, and the use of Pydantic Models.
Set up your GitHub environment by authenticating via the CLI:
gh auth login
You will need to install the GitHub CLI if you haven’t already (it’s already set up in the Nuvolos environment).
Ensure you have an organised workspace for this course.
If using
Nuvolos, you should start working from the folder
/files
:cd /files
If working locally (on your own machine), ensure you have a dedicated folder for this course. That is, don’t just use your Desktop or Documents folder.
Here’s a suggestion for creating a new folder and navigating to it:
mkdir ~/DS205 cd ~/DS205
Setting Up Your Environment
Option 1: Using Nuvolos (Simpler)
- Log into the Nuvolos Platform.
- Open the VS Code application within the DS205 environment.
Option 2: Running Locally on Your Computer
Ensure you have installed:
🛣️ Lab Roadmap
Part I: FastAPI Setup (15 min)
Note to class teachers: You can choose to either run this as a guided live-demo or let students follow the instructions on their own while you help those who get stuck. The URL generated by Nuvolos is likely to be the source of confusion, so make sure to clarify this.
🎯 ACTION POINTS
Clone the ASCOR API GitHub Repository into your working folder:
git clone https://github.com/lse-ds205/ascor-api.git cd ascor-api
Open the repository in VS Code. That is, click on File > Open Folder and select the
ascor-api
folder.This should keep things organised and make it easier to navigate the repository.
Open a Terminal inside VS Code, navigate to the repository folder and install the dependencies:
pip install -r requirements.txt
Run the starter FastAPI app:
uvicorn main:app --reload
You will see something like this:
INFO: Will watch for changes in these directories: ['/files/ascor-api'] INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: Started reloader process [6930] using StatReload INFO: Started server process [6932] INFO: Waiting for application startup. INFO: Application startup complete.
Test the API:
Nuvolos: You will need to discover your unique Nuvolos URL. The simplest way is to hover your mouse over the text
http://127.0.0.1:8000
in the terminal output and then hit ‘Ctrl’ (if on Windows) or ‘Cmd’ (if on Mac) and click with your mouse to open the link in a new tab.Alternatively, you can run the following command in the terminal to get the URL:
echo $VSCODE_PROXY_URI
Local Machine: Use the following URLs:
- API root:
http://127.0.0.1:8000/
- Documentation:
http://127.0.0.1:8000/docs
- API root:
Observe the auto-generated documentation for your API. There should only be one endpoint available at the moment.
Part II: Scaffold a Simple API Endpoint (20 min)
🗣️ TEACHING MOMENT
Note to class teachers: Remind you of the endpoint suggestions from the W02 Lecture, which were posted to the
ascor-api repository, under Issue #2. In particular, we will closely follow the proposal made by Bilal in our first implementation. Reinforce how we will start simple and then eventually refine the response structure and add more query parameters, in line with what was in the final slide of the lecture.
For this section, we will start by implementing a simple endpoint that returns a fixed response. We will then refine the response structure and add query parameters to filter the data.
Here are the details for the first endpoint:
📚 ASCOR API Endpoint Design:
/v1/country-data/{country}/{assessment_year}
Purpose: Retrieve area-level data for a specific country and assessment year.
Path Parameters
country
: Name of the country, spelled out (e.g., “United Kingdom”).assessment_year
: Year of the assessment data (e.g., 2024).
Expected Response
The response will be a simple JSON object indicating the area-level data for the country and year:
{"EP1" : "No",
"EP2" : "Yes",
"EP3" : "No",
...
}
🎯 ACTION POINTS
Add the following code to the
v1/app.py
file in the FastAPI app:@app.get("/v1/country-data/{country}/{assessment_year}") async def get_country_data(country: str, assessment_year: int): # Silly non-data-driven response for now return {"message": f"You requested data for {country} in {assessment_year}. Eventually, we will return the data here."}
Note: let’s start small. Don’t currently worry about the structure of the
indicators
dictionary. We will refine it in the next steps.Test it out! Open the browser and navigate to
http://IP:PORT/v1/country-data/Italy/2024
. ReplaceIP
andPORT
with the correct values. Ask your class teacher for help if you are unsure.If you need to specify a country that has a space in its name, replace the space with
%20
. For example, to get data for the United Kingdom, usehttp://IP:PORT/v1/country-data/United%20Kingdom/2024
.In Python, you can use the
requests
library to test the endpoint:import requests = "http://IP:PORT/v1/country-data/Italy/2024" url = requests.get(url) response # Confirm that the request was successful assert response.status_code == 200 # Get the response as a JSON object = response.json() data
Explore the auto-generated documentation by navigating to
http://IP:PORT/docs
. This is a great way to test your endpoint and see the expected parameters.Here’s a short video showing how to test the endpoint using the browser:
Part III: Implement the endpoint response (35 min)
Note to class teachers: It’s likely that pandas will be the major blocker, not the FastAPI code. If many students are struggling to write code for the necessary pandas operations, consider providing a code snippet that loads the data and filters it.
It’s time to actually return some data from the endpoint.
🎯 ACTION POINTS
Modify the
v1/app.py
file again.This time, add an import to pandas together with the other imports, then write code to load the
ASCOR_assessment_results.xlsx
data to a pandas DataFrame calleddf_assessments
.# Load the data = ... # Specify the correct path to the file filepath = pd.read_excel(filepath) df_assessments # Convert the date columns to datetime type so we can filter by year later 'Assessment date'] = pd.to_datetime(df_assessments['Assessment date']) df_assessments['Publication date'] = pd.to_datetime(df_assessments['Publication date']) df_assessments[
That is, you need to specify the correct path to the Excel file, relative to the root folder of the application (
ascor-api
).
✅ Click here when you are tired of trying
= "./data/TPI ASCOR data - 13012025/ASCOR_assessments_results.xlsx" filepath
The ./
at the beginning of the path indicates that we start from the root folder of the application – it is where the main.py
file is located.
Modify the
get_country_data
function to return the data for the specified country and year.The response for ‘United Kingdom’ in 2024 should look exactly like this:
{ "EP.1": "Partial", "EP.2": "Partial", "EP.3": "Partial", "CP.1": "Yes", "CP.2": "Partial", "CP.3": "No", "CP.4": "Partial", "CP.5": "Yes", "CP.6": "Partial", "CF.1": "No", "CF.2": "Exempt", "CF.3": "Yes", "CF.4": "", "country": "United Kingdom", "assessment_year": 2024 }
This might be challenging! You will need to filter the data based on the country and year, extract the relevant columns, rename the columns to match the expected response, replace missing values with an empty string, and return the data as a dictionary.
💡 Tip: Keep the
/docs
version of your API open on a separate browser. Every time you make a small change to it, use the ‘Try it out’ feature to see your implementation is working.
Part IV: Pushing Your Changes to GitHub (10 min)
Even if you haven’t been able to complete the implementation, let’s practice pushing your changes to GitHub.
🧑🏻🏫 TEACHING MOMENT
Follow these steps together with your class teacher to push your changes to GitHub.
Create a new branch in Git for your work:
git checkout -b feature/country-endpoint-<your-github-username>
That is, if your GitHub username is
johndoe
, the branch name should befeature/country-endpoint-johndoe
.Look at the changes you’ve made:
git status
This will show you the files you’ve modified.
Commit your changes:
git add . git commit -m "(WIP) Add a first version of the country endpoint"
Drop the
(WIP)
from the message if you are confident that your code is working.Push your branch and create a pull request:
git push origin feature/country-endpoint-<your-github-username>
Open a Pull Request on GitHub:
- Go to the ASCOR API repository.
- Click on the “Pull Requests” tab.
- Click on the “New Pull Request” button.
- Select your branch from the dropdown menu.
- Click on the “Create Pull Request” button.
- Add the following as the title:
WIP: Add a first version of the country endpoint
.
Jon will review your code and provide feedback on your implementation by the end of the week. You can still make changes to your code and push them to the same branch. Jon will see the updates automatically, you don’t need to open a new Pull Request.
Part V: Looking at a solution (10 min)
🧑🏻🏫 TEACHING MOMENT
Your class teacher will show you a possible solution to the implementation of the endpoint we have been working on. This will help you understand how to structure the code and use pandas to filter the data.
If you have a different way of solving the problem, that’s great! There are many ways to achieve the same result in programming. You will get feedback on your code regardless of the approach you take.