Welcome to the next step in our journey of building a personal tutor service with FastAPI. In the previous lesson, we focused on the TutorController, which manages tutoring sessions and handles student queries by interacting with both the model and service layers. Now, we will take a significant step forward by creating a RESTful API for our personal tutor service using FastAPI. We'll start by setting up the main FastAPI application, then adapt the TutorController to integrate with FastAPI's session management.
RESTful APIs are a way for different software systems to communicate over the internet. They provide a set of rules that allow programs to exchange data. FastAPI is a modern, fast (high-performance) web framework for building APIs with Python 3.7+ based on standard Python type hints. It is designed to be easy to use and to provide automatic interactive API documentation.
To get started with FastAPI, you can install it using pip by running the following command in your terminal or command prompt:
Additionally, to run the FastAPI application, you'll need to install Uvicorn, an ASGI server:
Now, we can use FastAPI to connect the components we've already built, allowing students to interact with our personal tutor service through a web interface. This will enable seamless communication between students and our tutoring service.
First, we need to initialize the FastAPI application:
Here, we import the FastAPI module and instantiate the FastAPI class to create our application object, app. We also give it a title, "Personal Tutor API," which will be displayed in the automatic API documentation that FastAPI generates. This object will be used to configure and run our web application.
FastAPI does not have built-in session management, but it's built on top of Starlette, which provides session handling capabilities. When you install FastAPI, Starlette comes bundled with it, giving you access to its middleware components.
A middleware is a function that works with every request before it's processed by any specific route handler. It sits between the server receiving the request and your route functions, allowing you to modify requests or responses globally.
We can add Starlette's SessionMiddleware to our FastAPI application to enable session management:
The SessionMiddleware handles creating, reading, and updating session data stored in cookies. The secret_key parameter is crucial for securing session data, as it's used to sign the session cookies to prevent tampering.
For our personal tutor service, we want to provide a user-friendly interface. FastAPI allows us to serve static files (CSS, JavaScript, images) and use templates to render HTML pages:
The StaticFiles class enables serving static files from the specified directory, and Jinja2Templates sets up template rendering with Jinja2, a powerful template engine for Python.
Next, we create an instance of our TutorController to handle the core operations of our personal tutor service:
This controller will manage tutoring sessions and process student queries, serving as the bridge between our API endpoints and the underlying service layer. By instantiating it at the application level, we ensure it's available to all route handlers.
FastAPI uses Pydantic for data validation. We can define a model for the query request to ensure we receive the correct data structure:
This model specifies that a query request must include a session_id and a query. FastAPI will automatically validate incoming requests against this model and return appropriate error responses if the data doesn't match.
To ensure each student has a unique identifier, we create a dependency function that checks for a student ID in the session and creates one if it doesn't exist:
This function will be used as a dependency in our route handlers, ensuring that each student has a unique ID before processing their requests.
Now that we've initialized our FastAPI application and created our controller instance, let's create the API endpoints that will allow students to interact with our personal tutor service. In FastAPI, routes are defined using decorators that specify the HTTP method and path.
This route handles GET requests to the root path (/). The @app.get("/") decorator tells FastAPI that this function should be called when a user visits the homepage. The function receives a Request object and uses the get_student_id dependency to ensure the student has an ID. It then returns a rendered HTML template, tutor.html, passing the request object to the template.
Next, let's define a route for creating new tutoring sessions:
This route handles POST requests to /api/create_session. We use POST instead of GET because we're creating a new resource (a tutoring session). The route uses the get_student_id dependency to identify the student. The controller's create_session method returns either a success response or an error tuple. If it's an error, we raise an HTTPException with the appropriate status code and message; otherwise, we return the data part of the response.
Finally, let's create a route for sending queries to the tutor:
This route handles POST requests to /api/send_query. It expects a request body that matches our QueryRequest model, automatically validating and parsing the JSON payload. We also use the get_student_id dependency as before. The controller's send_query method processes the query and returns either a success response or an error tuple, which we handle similarly to the create_session route.
To ensure consistent error responses across our API, we can add a custom exception handler for HTTPException:
This handler ensures that all HTTPException instances are converted to JSON responses with a consistent structure, making it easier for clients to handle errors.
Now that we've defined our routes and prepared our controller for integration with FastAPI, the final step is to set up the server to run our application. We'll use Uvicorn, an ASGI server, to serve our FastAPI application.
This code block does several important things:
-
The
if __name__ == "__main__":condition ensures that the server only starts when we run this file directly, not when it's imported by another module. -
The
uvicorn.run()function launches the ASGI server with our FastAPI application. The first argument,"main:app", tells Uvicorn where to find our application — in this case, theappvariable in themain.pyfile. This syntax allows us to run the main file directly with a command likepython main.pyinstead of having to use the uvicorn command-line interface. -
We set the host to
"0.0.0.0"to make the server accessible from any network interface, not just localhost. This is useful if you want to access the server from other devices on your network. -
The port is set to
3000, so our application will be available athttp://localhost:3000. -
The
reload=Trueparameter enables hot reloading, which automatically restarts the server when you make changes to your code. This is extremely helpful during development.
The TutorController has been designed to work seamlessly with FastAPI, handling student IDs and session management effectively. Let's examine its key methods and how they integrate with our API.
The create_session method accepts a student_id parameter from FastAPI's session management. It checks if the student ID is valid, creates a new tutoring session using the TutorService, and returns a success response with the session ID.
The send_query method is responsible for processing student queries. It receives the student ID, session ID, and the query content. After validating these parameters, it calls the process_query method on the TutorService to generate a response. The method includes comprehensive error handling, returning appropriate error responses for various scenarios.
To interact with our personal tutor service, a student can follow these steps:
-
Access the Index Route (
/): The student begins by accessing the index route of the API. This step ensures that a student session is established. A student session is a way to keep track of the student's interactions with the service. It is stored using FastAPI's session management, which utilizes cookies to maintain session data on the client side. The server responds with the tutor interface, ready for interaction. -
Create a Tutoring Session (
/api/create_session): Before sending a query, the student needs to create a new tutoring session. This is done by sending a request to the/api/create_sessionroute. The server will respond with a unique session ID, which is essential for identifying the tutoring session in subsequent interactions. The student session ensures that the tutoring session is associated with the correct student, allowing for personalized academic support. -
Send a Query (
/api/send_query): With the tutoring session established, the student can now send academic questions to the personal tutor. This involves sending a request to the/api/send_queryroute, including the session ID and the query content. The server processes the query using the DeepSeek model and responds with the tutor's explanation, allowing the student to continue the learning conversation. The student session helps maintain continuity in the conversation by linking the queries to the correct student and tutoring session.
By following these steps, a student can effectively receive personalized academic support from our personal tutor service, leveraging the RESTful API to manage tutoring sessions and exchange queries while utilizing student sessions for a seamless learning experience.
In this lesson, we successfully built a RESTful API for our personal tutor service using FastAPI. We set up a FastAPI application, defined routes for tutoring operations, and explored how the TutorController integrates with FastAPI's session management. This lesson marks a significant milestone in our course, as it brings together all the components we've developed so far into a functional web application that can deliver personalized academic support at scale.
As you move on to the practice exercises, take the opportunity to experiment with the FastAPI API and reinforce the concepts covered in this lesson. This hands-on practice will prepare you for further development and exploration of additional FastAPI features and RESTful API concepts. Keep up the great work, and I look forward to seeing your progress!
