💻 Week 02 Lab

Building APIs with FastAPI (Part I)

Author
Published

28 January 2025

🥅 Learning Goals
By the end of this lab, you should be able to: i) set up a basic FastAPI application, ii) implement a simple API endpoint, iii) test and debug API responses locally, and iv) refine API outputs using Pydantic models.
Image created with the AI embedded in MS Designer using the prompt 'abstract green and blue icon depicting the advanced stages of data wrangling, API design, and scalable pipelines for sustainability-focused data engineering.'

Last Updated: 27 January 17:30 to incorporate ideas from the morning session.

📋 Preparation

Before attending this lab, ensure that you:

  1. 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.

  2. Have reviewed the lecture content from Week 02, particularly the FastAPI Overview, RESTful Design Principles, and the use of Pydantic Models.

  3. 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).

  4. 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)
  1. Log into the Nuvolos Platform.
  2. 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

  1. Clone the ASCOR API GitHub Repository into your working folder:

    git clone https://github.com/lse-ds205/ascor-api.git
    cd ascor-api
  2. 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.

  3. Open a Terminal inside VS Code, navigate to the repository folder and install the dependencies:

    pip install -r requirements.txt
  4. 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.
  5. 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

    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

  1. 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.

  2. Test it out! Open the browser and navigate to http://IP:PORT/v1/country-data/Italy/2024. Replace IP and PORT 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, use http://IP:PORT/v1/country-data/United%20Kingdom/2024.

    In Python, you can use the requests library to test the endpoint:

    import requests
    
    url = "http://IP:PORT/v1/country-data/Italy/2024"
    
    response = requests.get(url)
    
    # Confirm that the request was successful
    assert response.status_code == 200
    
    # Get the response as a JSON object
    data = response.json()
  3. 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

  1. 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 called df_assessments.

    # Load the data
    filepath = ... # Specify the correct path to the file
    df_assessments = pd.read_excel(filepath)
    
    # Convert the date columns to datetime type so we can filter by year later
    df_assessments['Assessment date'] = pd.to_datetime(df_assessments['Assessment date'])
    df_assessments['Publication date'] = pd.to_datetime(df_assessments['Publication date'])

    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
filepath = "./data/TPI ASCOR data - 13012025/ASCOR_assessments_results.xlsx"

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.

  1. 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.

  1. 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 be feature/country-endpoint-johndoe.

  2. Look at the changes you’ve made:

    git status

    This will show you the files you’ve modified.

  3. 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.

  4. Push your branch and create a pull request:

    git push origin feature/country-endpoint-<your-github-username>
  5. 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.